From 6003a768db2b013216715ea60692ddae35524d44 Mon Sep 17 00:00:00 2001
From: emudave <emudave@gmail.com>
Date: Mon, 7 Feb 2011 22:06:07 +0000
Subject: [PATCH] first check-in of Cyclone 0.069 under GPLv2 and MAME License.
 Pico Disa.c/h included too

---
 Cyclone/Cyclone.dsp       | 170 ++++++++
 Cyclone/Cyclone.dsw       |  29 ++
 Cyclone/Cyclone.h         |  45 ++
 Cyclone/Cyclone.txt       | 390 ++++++++++++++++++
 Cyclone/DoClean.bat       |  20 +
 Cyclone/Ea.cpp            | 296 +++++++++++++
 Cyclone/License-GPLv2.txt | 339 +++++++++++++++
 Cyclone/License.txt       |  37 ++
 Cyclone/Main.cpp          | 277 +++++++++++++
 Cyclone/OpAny.cpp         | 117 ++++++
 Cyclone/OpArith.cpp       | 521 +++++++++++++++++++++++
 Cyclone/OpBranch.cpp      | 376 +++++++++++++++++
 Cyclone/OpLogic.cpp       | 523 +++++++++++++++++++++++
 Cyclone/OpMove.cpp        | 454 ++++++++++++++++++++
 Cyclone/app.h             |  85 ++++
 Pico/Disa.c               | 846 ++++++++++++++++++++++++++++++++++++++
 Pico/Disa.h               |  20 +
 test.txt                  |   1 -
 18 files changed, 4545 insertions(+), 1 deletion(-)
 create mode 100644 Cyclone/Cyclone.dsp
 create mode 100644 Cyclone/Cyclone.dsw
 create mode 100644 Cyclone/Cyclone.h
 create mode 100644 Cyclone/Cyclone.txt
 create mode 100644 Cyclone/DoClean.bat
 create mode 100644 Cyclone/Ea.cpp
 create mode 100644 Cyclone/License-GPLv2.txt
 create mode 100644 Cyclone/License.txt
 create mode 100644 Cyclone/Main.cpp
 create mode 100644 Cyclone/OpAny.cpp
 create mode 100644 Cyclone/OpArith.cpp
 create mode 100644 Cyclone/OpBranch.cpp
 create mode 100644 Cyclone/OpLogic.cpp
 create mode 100644 Cyclone/OpMove.cpp
 create mode 100644 Cyclone/app.h
 create mode 100644 Pico/Disa.c
 create mode 100644 Pico/Disa.h
 delete mode 100644 test.txt

diff --git a/Cyclone/Cyclone.dsp b/Cyclone/Cyclone.dsp
new file mode 100644
index 0000000..7085e11
--- /dev/null
+++ b/Cyclone/Cyclone.dsp
@@ -0,0 +1,170 @@
+# Microsoft Developer Studio Project File - Name="Cyclone" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Cyclone - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "Cyclone.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Cyclone.mak" CFG="Cyclone - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Cyclone - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Cyclone - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Cyclone - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 user32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "Cyclone - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "Cyclone - Win32 Release"
+# Name "Cyclone - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\Cyclone.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\Ea.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpAny.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpArith.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpBranch.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpLogic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpMove.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\app.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Cyclone.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Group "Output"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\Cyclone.asm
+# End Source File
+# Begin Source File
+
+SOURCE=.\Cyclone.s
+# End Source File
+# End Group
+# Begin Group "Disassembler"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Pico\Disa.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\Pico\Disa.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\EmuInfo\68000\680x0bin.txt
+# End Source File
+# Begin Source File
+
+SOURCE=..\bits.txt
+# End Source File
+# End Target
+# End Project
diff --git a/Cyclone/Cyclone.dsw b/Cyclone/Cyclone.dsw
new file mode 100644
index 0000000..a783183
--- /dev/null
+++ b/Cyclone/Cyclone.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Cyclone"=.\Cyclone.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/Cyclone/Cyclone.h b/Cyclone/Cyclone.h
new file mode 100644
index 0000000..99fb1fc
--- /dev/null
+++ b/Cyclone/Cyclone.h
@@ -0,0 +1,45 @@
+
+// Cyclone 68000 Emulator - Header File
+
+// This code is licensed under the GNU General Public License version 2.0 and the MAME License.
+// You can choose the license that has the most advantages for you.
+
+// SVN repository can be found at http://code.google.com/p/cyclone68000/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int CycloneVer; // Version number of library
+
+struct Cyclone
+{
+  unsigned int d[8];   // [r7,#0x00]
+  unsigned int a[8];   // [r7,#0x20]
+  unsigned int pc;     // [r7,#0x40] Memory Base+PC
+  unsigned char srh;   // [r7,#0x44] Status Register high (T_S__III)
+  unsigned char xc;    // [r7,#0x45] Extend flag (____??X?)
+  unsigned char flags; // [r7,#0x46] Flags (ARM order: ____NZCV)
+  unsigned char irq;   // [r7,#0x47] IRQ level
+  unsigned int osp;    // [r7,#0x48] Other Stack Pointer (USP/SSP)
+  unsigned int vector; // [r7,#0x50] IRQ vector (temporary)
+  int pad1[3];
+  int cycles;          // [r7,#0x5c]
+  int membase;         // [r7,#0x60] Memory Base (ARM address minus 68000 address)
+  unsigned int   (*checkpc)(unsigned int pc); // [r7,#0x64] - Called to recalc Memory Base+pc
+  unsigned char  (*read8  )(unsigned int a);  // [r7,#0x68]
+  unsigned short (*read16 )(unsigned int a);  // [r7,#0x6c]
+  unsigned int   (*read32 )(unsigned int a);  // [r7,#0x70]
+  void (*write8 )(unsigned int a,unsigned char  d); // [r7,#0x74]
+  void (*write16)(unsigned int a,unsigned short d); // [r7,#0x78]
+  void (*write32)(unsigned int a,unsigned int   d); // [r7,#0x7c]
+  unsigned char  (*fetch8 )(unsigned int a);  // [r7,#0x80]
+  unsigned short (*fetch16)(unsigned int a);  // [r7,#0x84]
+  unsigned int   (*fetch32)(unsigned int a);  // [r7,#0x88]
+};
+
+void CycloneRun(struct Cyclone *pcy);
+
+#ifdef __cplusplus
+} // End of extern "C"
+#endif
diff --git a/Cyclone/Cyclone.txt b/Cyclone/Cyclone.txt
new file mode 100644
index 0000000..0b0d062
--- /dev/null
+++ b/Cyclone/Cyclone.txt
@@ -0,0 +1,390 @@
+
+      _____            __                                     
+     / ___/__ __ ____ / /___   ___  ___   ___________________ 
+    / /__ / // // __// // _ \ / _ \/ -_) ___________________  
+    \___/ \_, / \__//_/ \___//_//_/\__/ ___________________   
+         /___/                                                
+         ___________________  ____ ___   ___   ___   ___      
+        ___________________  / __// _ \ / _ \ / _ \ / _ \     
+       ___________________  / _ \/ _  // // // // // // /     
+                            \___/\___/ \___/ \___/ \___/      
+                                                              
+___________________________________________________________________________
+
+
+This code is licensed under the GNU General Public License version 2.0 and the MAME License.
+You can choose the license that has the most advantages for you.
+
+___________________________________________________________________________
+
+
+What is it?
+-----------
+
+Cyclone 68000 is an emulator for the 68000 microprocessor, written in ARM 32-bit assembly.
+It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret 68000
+code as fast as possible.
+
+Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode.
+
+Developers:
+-----------
+
+Dave / FinalDave: emudave(atsymbol)gmail.com
+
+
+What's New
+----------
+v0.069
+  + Added SBCD and the flags for ABCD/SBCD. Score and time now works in games such as
+    Rolling Thunder 2, Ghouls 'N Ghosts
+  + Fixed a problem with addx and subx with 8-bit and 16-bit values.
+    Ghouls 'N' Ghosts now works!
+
+v0.068
+  + Added ABCD opcode (Streets of Rage works now!)
+
+v0.067
+  + Added dbCC (After Burner)
+  + Added asr EA (Sonic 1 Boss/Labyrinth Zone)
+  + Added andi/ori/eori ccr (Altered Beast)
+  + Added trap (After Burner)
+  + Added special case for move.b (a7)+ and -(a7), stepping by 2
+    After Burner is playable! Eternal Champions shows more
+  + Fixed lsr.b/w zero flag (Ghostbusters)
+    Rolling Thunder 2 now works!
+  + Fixed N flag for .b and .w arithmetic. Golden Axe works!
+
+v0.066
+  + Fixed a stupid typo for exg (orr r10,r10, not orr r10,r8), which caused alignment
+    crashes on Strider
+
+v0.065
+  + Fixed a problem with immediate values - they weren't being shifted up correctly for some
+    opcodes. Spiderman works, After Burner shows a bit of graphics.
+  + Fixed a problem with EA:"110nnn" extension word. 32-bit offsets were being decoded as 8-bit
+    offsets by mistake. Castlevania Bloodlines seems fine now.
+  + Added exg opcode
+  + Fixed asr opcode (Sonic jumping left is fixed)
+  + Fixed a problem with the carry bit in rol.b (Marble Madness)
+
+v0.064
+  + Added rtr
+  + Fixed addq/subq.l (all An opcodes are 32-bit) (Road Rash)
+  + Fixed various little timings
+
+v0.063
+  + Added link/unlk opcodes
+  + Fixed various little timings
+  + Fixed a problem with dbCC opcode being emitted at set opcodes
+  + Improved long register access, the EA fetch now does ldr r0,[r7,r0,lsl #2] whenever
+     possible, saving 1 or 2 cycles on many opcodes, which should give a nice speed up.
+  + May have fixed N flag on ext opcode?
+  + Added dasm for link opcode.
+
+v0.062
+  * I was a bit too keen with the Arithmetic opcodes! Some of them should have been abcd,
+    exg and addx. Removed the incorrect opcodes, pending re-adding them as abcd, exg and addx.
+  + Changed unknown opcodes to act as nops.
+    Not very technical, but fun - a few more games show more graphics ;)
+
+v0.060
+  + Fixed divu (EA intro)
+  + Added sf (set false) opcode - SOR2
+  * Todo: pea/link/unlk opcodes
+
+v0.059: Added remainder to divide opcodes.
+
+
+ARM Register Usage
+------------------
+
+See source code for up to date of register usage, however a summary is here:
+
+  r0-3: Temporary registers
+  r4  : Current PC + Memory Base (i.e. pointer to next opcode)
+  r5  : Cycles remaining
+  r6  : Pointer to Opcode Jump table
+  r7  : Pointer to Cpu Context
+  r8  : Current Opcode
+  r9  : Flags (NZCV) in highest four bits
+ (r10 : Temporary source value or Memory Base)
+ (r11 : Temporary register)
+
+
+How to Compile
+--------------
+
+Like Starscream and A68K, Cyclone uses a 'Core Creator' program which calculates and outputs
+all possible 68000 Opcodes and a jump table into files called Cyclone.s and .asm
+It then assembles these files into Cyclone.o and .obj
+
+Cyclone.o is the GCC assembled version and Cyclone.obj is the Microsoft assembled version.
+
+First unzip "Cyclone.zip" into a "Cyclone" directory.
+If you are compiling for Windows CE, find ARMASM.EXE (the Microsoft ARM assembler) and
+put it in the directory as well or put it on your path.
+
+Open up Cyclone.dsw in Visual Studio 6.0, compile and run the project.
+Cyclone.obj and Cyclone.o will be created.
+
+Compiling without Visual C++
+----------------------------
+If you aren't using Visual C++, it still shouldn't be too hard to compile, just get a C compiler,
+compile all the CPPs and C file, link them into an EXE, and run the exe.
+
+  e.g. gcc Main.cpp OpAny.cpp OpArith.cpp OpBranch.cpp OpLogic.cpp OpMove.cpp Disa.c
+  Main.exe
+
+
+Adding to your project
+----------------------
+
+To add Cyclone to you project, add Cyclone.o or obj, and include Cyclone.h
+There is one structure: 'struct Cyclone', and one function: CycloneRun
+
+Don't worry if this seem very minimal - its all you need to run as many 68000s as you want.
+It works with both C and C++.
+
+Byteswapped Memory
+------------------
+
+If you have used Starscream, A68K or Turbo68K or similar emulators you'll be familiar with this!
+
+Any memory which the 68000 can access directly must be have every two bytes swapped around.
+This is to speed up 16-bit memory accesses, because the 68000 has Big-Endian memory
+and ARM has Little-Endian memory.
+
+Now you may think you only technically have to byteswap ROM, not RAM, because
+16-bit RAM reads go through a memory handler and you could just return (mem[a]<<8) | mem[a+1].
+
+This would work, but remember some systems can execute code from RAM as well as ROM, and
+that would fail.
+So it's best to use byteswapped ROM and RAM if the 68000 can access it directly.
+It's also faster for the memory handlers, because you can do this:
+  
+  return *(unsigned short *)(mem+a)
+
+
+Declaring a Memory handlers
+---------------------------
+
+Before you can reset or execute 68000 opcodes you must first set up a set of memory handlers.
+There are 7 functions you have to set up per CPU, like this:
+
+  static unsigned int   MyCheckPc(unsigned int pc)
+  static unsigned char  MyRead8  (unsigned int a)
+  static unsigned short MyRead16 (unsigned int a)
+  static unsigned int   MyRead32 (unsigned int a)
+  static void MyWrite8 (unsigned int a,unsigned char  d)
+  static void MyWrite16(unsigned int a,unsigned short d)
+  static void MyWrite32(unsigned int a,unsigned int   d)
+
+You can think of these functions representing the 68000's memory bus.
+The Read and Write functions are called whenever the 68000 reads or writes memory.
+For example you might set MyRead8 like this:
+
+  unsigned char MyRead8(unsigned int a)
+  {
+    a&=0xffffff; // Clip address to 24-bits
+
+    if (a<RomLength) return RomData[a^1]; // ^1 because the memory is byteswapped
+    if (a>=0xe00000) return RamData[(a^1)&0xffff];
+    return 0xff; // Out of range memory access
+  }
+
+The other 5 read/write functions are similar. I'll describe the CheckPc function later on.
+
+Declaring a CPU Context
+-----------------------
+
+To declare a CPU simple declare a struct Cyclone in your code. For example to declare
+two 68000s:
+
+  struct Cyclone MyCpu;
+  struct Cyclone MyCpu2;
+
+It's probably a good idea to initialise the memory to zero:
+
+  memset(&MyCpu, 0,sizeof(MyCpu));
+  memset(&MyCpu2,0,sizeof(MyCpu2));
+
+Next point to your memory handlers:
+
+  MyCpu.checkpc=MyCheckPc;
+  MyCpu.read8  =MyRead8;
+  MyCpu.read16 =MyRead16;
+  MyCpu.read32 =MyRead32;
+  MyCpu.write8 =MyWrite8;
+  MyCpu.write16=MyWrite16;
+  MyCpu.write32=MyWrite32;
+
+You also need to point the fetch handlers - for most systems out there you can just
+point them at the read handlers:
+  MyCpu.fetch8  =MyRead8;
+  MyCpu.fetch16 =MyRead16;
+  MyCpu.fetch32 =MyRead32;
+
+( Why a different set of function pointers for fetch?
+  Well there are some systems, the main one being CPS2, which return different data
+  depending on whether the 'fetch' line on the 68000 bus is high or low.
+  If this is the case, you can set up different functions for fetch reads.
+  Generally though you don't need to. )
+
+Now you are nearly ready to reset the 68000, except you need one more function: checkpc().
+
+The checkpc() function
+----------------------
+
+When Cyclone reads opcodes, it doesn't use a memory handler every time, this would be
+far too slow, instead it uses a direct pointer to ARM memory.
+For example if your Rom image was at 0x3000000 and the program counter was $206,
+Cyclone's program counter would be 0x3000206.
+
+The difference between an ARM address and a 68000 address is also stored in a variable called
+'membase'. In the above example it's 0x3000000. To retrieve the real PC, Cyclone just
+subtracts 'membase'.
+
+When a long jump happens, Cyclone calls checkpc(). If the PC is in a different bank,
+for example Ram instead of Rom, change 'membase', recalculate the new PC and return it:
+
+static int MyCheckPc(unsigned int pc)
+{
+  pc-=MyCpu.membase; // Get the real program counter
+
+  if (pc<RomLength) MyCpu.membase=(int)RomMem;          // Jump to Rom
+  if (pc>=0xff0000) MyCpu.membase=(int)RamMem-0xff0000; // Jump to Ram
+
+  return MyCpu.membase+pc; // New program counter
+}
+
+Notice that the membase is always ARM address minus 68000 address.
+
+The above example doesn't consider mirrored ram, but for an example of what to do see
+PicoDrive (in Memory.cpp).
+
+
+Almost there - Reset the 68000!
+-------------------------------
+
+Next we need to Reset the 68000 to get the initial Program Counter and Stack Pointer. This
+is obtained from addresses 000000 and 000004.
+
+Here is code which resets the 68000 (using your memory handlers):
+
+  MyCpu.srh=0x27; // Set supervisor mode
+  MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer
+  MyCpu.membase=0;
+  MyCpu.pc=MyCpu.checkpc(MyCpu.read32(4)); // Get Program Counter
+
+And that's ready to go.
+
+
+Executing the 68000
+-------------------
+
+To execute the 68000, set the 'cycles' variable to the number of cycles you wish to execute,
+and then call CycloneRun with a pointer to the Cyclone structure.
+
+e.g.:
+  // Execute 1000 cycles on the 68000:
+  MyCpu.cycles=1000; CycloneRun(&MyCpu);
+
+For each opcode, the number of cycles it took is subtracted and the function returns when
+it reaches 0.
+
+e.g.
+  // Execute one instruction on the 68000:
+  MyCpu.cycles=0; CycloneRun(&MyCpu);
+  printf("  The opcode took %d cycles\n", -MyCpu.cycles);
+
+You should try to execute as many cycles as you can for maximum speed.
+The number actually executed may be slightly more than requested, i.e. cycles may come
+out with a small negative value:
+
+e.g.
+  int todo=12000000/60; // 12Mhz, for one 60hz frame
+  MyCpu.cycles=todo; CycloneRun(&MyCpu);
+  printf("  Actually executed %d cycles\n", todo-MyCpu.cycles);
+
+To calculate the number of cycles executed, use this formula:
+  Number of cycles requested - Cycle counter at the end
+
+
+Interrupts
+----------
+
+Causing an interrupt is very simple, simply set the irq variable in the Cyclone structure
+to the IRQ number.
+To lower the IRQ line, set it to zero.
+
+e.g:
+  MyCpu.irq=6; // Interrupt level 6
+  MyCpu.cycles=20000; CycloneRun(&MyCpu);
+
+Note that the interrupt is not actually processed until the next call to CycloneRun,
+and the interrupt may not be taken until the 68000 interrupt mask is changed to allow it.
+
+( The IRQ isn't checked on exiting from a memory handler: I don't think this will cause
+  me any trouble because I've never needed to trigger an interrupt from a memory handler,
+  but if someone needs to, let me know...)
+
+Accessing Cycle Counter
+-----------------------
+
+The cycle counter in the Cyclone structure is not, by default, updated before
+calling a memory handler, only at the end of an execution.
+
+If you do need to read the cycle counter inside memory handlers, there is a
+bitfield called 'Debug' in Cyclone/Main.cpp.
+You can try setting Debug to 1 and then making the Cyclone library.
+This will add extra instructions so Cyclone writes register r5 back into the structure.
+
+If you need to *modify* cycles in a memory handler, set Debug to 3, this will read back
+the cycle counter as well.
+
+Accessing Program Counter and registers
+---------------------------------------
+
+You can read Cyclone's registers directly from the structure at any time (as far as I know).
+
+The Program Counter, should you need to read or write it, is stored with membase
+added on. So use this formula to calculate the real 68000 program counter:
+
+  pc = MyCpu.pc - MyCpu.membase;
+
+The program counter is stored in r4 during execution, and isn't written back to the
+structure until the end of execution, which means you can't read normally real it from
+a memory handler.
+However you can try setting Debug to 4 and then making the Cyclone library, this will
+write back r4 to the structure.
+
+You can't access the flags from a handler either. I can't imagine why anyone would particularly
+need to do this, but if you do e-mail me and I'll add another bit to 'Debug' ;)
+
+
+Emulating more than one CPU
+---------------------------
+
+Since everything is based on the structures, emulating more than one cpu at the same time
+is just a matter of declaring more than one structures and timeslicing. You can emulate
+as many 68000s as you want.
+Just set up the memory handlers for each cpu and run each cpu for a certain number of cycles.
+
+e.g.
+  // Execute 1000 cycles on 68000 #1:
+  MyCpu.cycles=1000; CycloneRun(&MyCpu);
+
+  // Execute 1000 cycles on 68000 #2:
+  MyCpu2.cycles=1000; CycloneRun(&MyCpu2);
+
+
+Thanks to...
+------------
+
+* All the previous code-generating assembler cpu core guys!
+  Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson
+    and Bart Trzynadlowski
+
+* Charles Macdonald, for researching just about every console ever
+* MameDev+FBA, for keeping on going and going and going
diff --git a/Cyclone/DoClean.bat b/Cyclone/DoClean.bat
new file mode 100644
index 0000000..e0119d4
--- /dev/null
+++ b/Cyclone/DoClean.bat
@@ -0,0 +1,20 @@
+ren Cyclone.obj Cyclone.ob_
+
+del Cyclone.asm
+del Cyclone.s
+del Cyclone.exe
+del *.obj
+del vc60.idb
+del vc60.pdb
+del Cyclone.plg
+del Cyclone.ncb
+del Cyclone.pch
+del Cyclone.ilk
+del Cyclone.pdb
+
+del /q Release\*.*
+rd  Release
+del /q Debug\*.*
+rd  Debug
+
+ren Cyclone.ob_ Cyclone.obj
diff --git a/Cyclone/Ea.cpp b/Cyclone/Ea.cpp
new file mode 100644
index 0000000..b1a3340
--- /dev/null
+++ b/Cyclone/Ea.cpp
@@ -0,0 +1,296 @@
+
+#include "app.h"
+
+// ---------------------------------------------------------------------------
+// Gets the offset of a register for an ea, and puts it in 'r'
+// Shifted left by 'shift'
+// Doesn't trash anything
+static int EaCalcReg(int r,int ea,int mask,int forceor,int shift)
+{
+  int i=0,low=0,needor=0;
+  int lsl=0;
+
+  for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is
+  mask&=0xf<<low; // This is the max we can do
+
+  if (ea>=8) needor=1; // Need to OR to access A0-7
+
+  if ((mask>>low)&8) if (ea&8) needor=0; // Ah - no we don't actually need to or, since the bit is high in r8
+
+  if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;)
+
+  ot("  and r%d,r8,#0x%.4x\n",r,mask);
+
+  // Find out amount to shift left:
+  lsl=shift-low;
+
+  if (lsl)
+  {
+    ot("  mov r%d,r%d,",r,r);
+    if (lsl>0) ot("lsl #%d\n", lsl);
+    else       ot("lsr #%d\n",-lsl);
+  }
+
+  if (needor) ot("  orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<<shift);
+  return 0;
+}
+
+// EaCalc - ARM Register 'a' = Effective Address
+// Trashes r0,r2 and r3
+int EaCalc(int a,int mask,int ea,int size)
+{
+  char text[32]="";
+  int func=0;
+
+  DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
+  func=0x68+(size<<2); // Get correct read handler
+
+  if (ea<0x10)
+  {
+    int lsl=2;
+    if (size>=2) lsl=0; // Saves one opcode
+
+    ot(";@ EaCalc : Get register index into r%d:\n",a);
+
+    EaCalcReg(a,ea,mask,0,lsl);
+    return 0;
+  }
+  
+  ot(";@ EaCalc : Get '%s' into r%d:\n",text,a);
+  // (An), (An)+, -(An):
+  if (ea<0x28)
+  {
+    int step=1<<size;
+
+    if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1
+
+    EaCalcReg(2,ea,mask,0,2);
+    ot("  ldr r%d,[r7,r2]\n",a);
+
+    if ((ea&0x38)==0x18)
+    {
+      ot("  add r3,r%d,#%d ;@ Post-increment An\n",a,step);
+      ot("  str r3,[r7,r2]\n");
+    }
+
+    if ((ea&0x38)==0x20)
+    {
+      ot("  sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step);
+      ot("  str r%d,[r7,r2]\n",a);
+    }
+
+    if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles
+    else                 Cycles+=size<2 ? 4:8;  // (An),(An)+ Extra cycles
+    return 0;
+  }
+
+  if (ea<0x30) // ($nn,An)
+  {
+    EaCalcReg(2,8,mask,0,2);
+    ot("  ldr r2,[r7,r2]\n");
+    ot("  ldrsh r0,[r4],#2 ;@ Fetch offset\n");
+    ot("  add r%d,r0,r2 ;@ Add on offset\n",a);
+    Cycles+=size<2 ? 8:12; // Extra cycles
+    return 0;
+  }
+
+  if (ea<0x38) // ($nn,An,Rn)
+  {
+    ot(";@ Get extension word into r3:\n");
+    ot("  ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n");
+    ot("  mov r2,r3,lsr #10\n");
+    ot("  tst r3,#0x0800 ;@ Is Rn Word or Long\n");
+    ot("  and r2,r2,#0x3c ;@ r2=Index of Rn\n");
+    ot("  mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n");
+    ot("  ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");
+    ot("  ldrne   r2,[r7,r2] ;@ r2=Rn.l\n");
+    ot("  add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n");
+
+    EaCalcReg(2,8,mask,1,2);
+    ot("  ldr r2,[r7,r2]\n");
+    ot("  add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a);
+    Cycles+=size<2 ? 10:14; // Extra cycles
+    return 0;
+  }
+
+  if (ea==0x38)
+  {
+    ot("  ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a);
+    Cycles+=size<2 ? 8:12; // Extra cycles
+    return 0;
+  }
+
+  if (ea==0x39)
+  {
+    ot("  ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n");
+    ot("  ldrh r0,[r4],#2\n");
+    ot("  orr r%d,r0,r2,lsl #16\n",a);
+    Cycles+=size<2 ? 12:16; // Extra cycles
+    return 0;
+  }
+
+  if (ea==0x3a)
+  {
+    ot("  ldr r0,[r7,#0x60] ;@ Get Memory base\n");
+    ot("  sub r0,r4,r0 ;@ Real PC\n");
+    ot("  ldrsh r2,[r4],#2 ;@ Fetch extension\n");
+    ot("  add r%d,r0,r2 ;@ ($nn,PC)\n",a);
+    Cycles+=size<2 ? 8:12; // Extra cycles
+    return 0;
+  }
+
+  if (ea==0x3b) // ($nn,pc,Rn)
+  {
+    ot(";@ Get extension word into r3:\n");
+    ot("  ldrh r3,[r4]\n");
+    ot("  mov r2,r3,lsr #10\n");
+    ot("  tst r3,#0x0800 ;@ Is Rn Word or Long\n");
+    ot("  and r2,r2,#0x3c ;@ r2=Index of Rn\n");
+    ot("  mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n");
+    ot("  ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");
+    ot("  ldrne   r2,[r7,r2] ;@ r2=Rn.l\n");
+    ot("  add r2,r2,r0,asr #24 ;@ r2=Disp+Rn\n");
+    ot("  ldr r0,[r7,#0x60] ;@ Get Memory base\n");
+    ot("  add r2,r2,r4 ;@ r2=Disp+Rn + Base+PC\n");
+    ot("  add r4,r4,#2 ;@ Increase PC\n");
+    ot("  sub r%d,r2,r0 ;@ r%d=Disp+PC+Rn\n",a,a);
+    Cycles+=size<2 ? 10:14; // Extra cycles
+    return 0;
+  }
+
+  if (ea==0x3c)
+  {
+    if (size<2)
+    {
+      ot("  ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a);
+      Cycles+=4; // Extra cycles
+      return 0;
+    }
+
+    ot("  ldrh r2,[r4],#2 ;@ Fetch immediate value\n");
+    ot("  ldrh r0,[r4],#2\n");
+    ot("  orr r%d,r0,r2,lsl #16\n",a);
+    Cycles+=8; // Extra cycles
+    return 0;
+  }
+
+  return 1;
+}
+
+// ---------------------------------------------------------------------------
+// Read effective address in (ARM Register 'a') to ARM register 'v'
+// 'a' and 'v' can be anything but 0 is generally best (for both)
+// If (ea<0x10) nothing is trashed, else r0-r3 is trashed
+// If 'top' is 1, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000
+// Otherwise the ARM register v is sign extended, e.g. 0xc000 -> 0xffffc000
+
+int EaRead(int a,int v,int ea,int size,int top)
+{
+  char text[32]="";
+  int shift=0;
+  
+  shift=32-(8<<size);
+
+  DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
+
+  if (ea<0x10)
+  {
+    int lsl=2;
+    if (size>=2) lsl=0; // Having a lsl #2 here saves one opcode
+
+    ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);
+
+    if (lsl==0) ot("  ldr r%d,[r7,r%d,lsl #2]\n",v,a);
+    else        ot("  ldr%s r%d,[r7,r%d]\n",Sarm[size&3],v,a);
+
+    if (top && shift) ot("  mov r%d,r%d,asl #%d\n",v,v,shift);
+
+    ot("\n"); return 0;
+  }
+
+  ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v);
+
+  if (ea==0x3c)
+  {
+    int asl=0;
+
+    if (top) asl=shift;
+
+    if (v!=a || asl) ot("  mov r%d,r%d,asl #%d\n",v,a,asl);
+    ot("\n"); return 0;
+  }
+
+  if (a!=0) ot("  mov r0,r%d\n",a);
+
+  if (ea>=0x3a && ea<=0x3b) MemHandler(2,size); // Fetch
+  else                      MemHandler(0,size); // Read
+
+  if (v!=0 || shift) ot("  mov r%d,r0,asl #%d\n",v,shift);
+  if (top==0 && shift) ot("  mov r%d,r%d,asr #%d\n",v,v,shift);
+
+  ot("\n"); return 0;
+}
+
+// Return 1 if we can read this ea
+int EaCanRead(int ea,int size)
+{
+  if (size<0)
+  {
+    // LEA:
+    // These don't make sense?:
+    if (ea<0x10) return 0; // Register
+    if (ea==0x3c) return 0; // Immediate
+    if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An
+  }
+
+  if (ea<=0x3c) return 1;
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+// Write effective address (ARM Register 'a') with ARM register 'v'
+// Trashes r0-r3, 'a' can be 0 or 2+, 'v' can be 1 or higher
+// If a==0 and v==1 it's faster though.
+int EaWrite(int a,int v,int ea,int size,int top)
+{
+  char text[32]="";
+  int shift=0;
+
+  if (top) shift=32-(8<<size);
+
+  DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
+
+  if (ea<0x10)
+  {
+    int lsl=2;
+    if (size>=2) lsl=0; // Having a lsl #2 here saves one opcode
+
+    ot(";@ EaWrite: r%d into register[r%d]:\n",v,a);
+    if (shift) ot("  mov r%d,r%d,asr #%d\n",v,v,shift);
+
+    if (lsl==0) ot("  str r%d,[r7,r%d,lsl #2]\n",v,a);
+    else        ot("  str%s r%d,[r7,r%d]\n",Narm[size&3],v,a);
+
+    ot("\n"); return 0;
+  }
+
+  ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a);
+
+  if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; }
+
+  if (a!=0 && v!=0)  ot("  mov r0,r%d\n",a);
+  if (v!=1 || shift) ot("  mov r1,r%d,asr #%d\n",v,shift);
+  if (a!=0 && v==0)  ot("  mov r0,r%d\n",a);
+
+  MemHandler(1,size); // Call write handler
+
+  ot("\n"); return 0;
+}
+
+// Return 1 if we can write this ea
+int EaCanWrite(int ea)
+{
+  if (ea<=0x3b) return 1;
+  return 0;
+}
+// ---------------------------------------------------------------------------
diff --git a/Cyclone/License-GPLv2.txt b/Cyclone/License-GPLv2.txt
new file mode 100644
index 0000000..0a98ec0
--- /dev/null
+++ b/Cyclone/License-GPLv2.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
\ No newline at end of file
diff --git a/Cyclone/License.txt b/Cyclone/License.txt
new file mode 100644
index 0000000..a7be9de
--- /dev/null
+++ b/Cyclone/License.txt
@@ -0,0 +1,37 @@
+This code is licensed under the GNU General Public License version 2.0 and the MAME License.
+You can choose the license that has the most advantages for you.
+
+The GNU General Public License is included here in 'License-GPLv2.txt'
+
+The MAME License is quoted here:
+
+
+Redistribution and use of this code or any derivative works are permitted
+provided that the following conditions are met:
+
+* Redistributions may not be sold, nor may they be used in a commercial
+product or activity.
+
+* Redistributions that are modified from the original source must include the
+complete source code, including the source code for all components used by a
+binary built from the modified sources. However, as a special exception, the
+source code distributed need not include anything that is normally distributed
+(in either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+* Redistributions must reproduce the above copyright notice, this list of
+conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Cyclone/Main.cpp b/Cyclone/Main.cpp
new file mode 100644
index 0000000..29dfb3e
--- /dev/null
+++ b/Cyclone/Main.cpp
@@ -0,0 +1,277 @@
+
+#include "app.h"
+
+static FILE *AsmFile=NULL;
+
+static int CycloneVer=0x0069; // Version number of library
+int *CyJump=NULL; // Jump table
+int ms=0; // If non-zero, output in Microsoft ARMASM format
+char *Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1,2
+char *Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2
+int Cycles=0; // Current cycles for opcode
+int Amatch=1; // If one, try to match A68K timing
+int Accu=-1; // Accuracy
+int Debug=0; // Debug info
+
+void ot(char *format, ...)
+{
+  va_list valist=NULL;
+  va_start(valist,format);
+  if (AsmFile) vfprintf(AsmFile,format,valist);
+  va_end(valist);
+}
+
+void ltorg()
+{
+  if (ms) ot("  LTORG\n");
+  else    ot("  .ltorg\n");
+}
+
+static void PrintException()
+{
+  ot("  ;@ Cause an Exception - Vector in [r7,#0x50]\n");
+  ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+  ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");
+  OpPush32();
+  OpPushSr(1);
+  ot("  ldr r0,[r7,#0x50] ;@ Get Vector\n");
+  ot(";@ Read IRQ Vector:\n");
+  MemHandler(0,2);
+  ot("  add r0,r0,r10 ;@ r0 = Memory Base + New PC\n");
+  ot("  mov lr,pc\n");
+  ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
+  ot("  mov r4,r0\n");
+  ot("\n");
+
+  // todo - make Interrupt code use this function as well
+}
+
+// Trashes r0
+void CheckInterrupt()
+{
+  ot(";@ CheckInterrupt:\n");
+  ot("  ldrb r0,[r7,#0x47] ;@ Get IRQ level\n");
+  ot("  tst r0,r0\n");
+  ot("  blne DoInterrupt\n");
+  ot("\n");
+}
+
+static void PrintFramework()
+{
+  ot(";@ --------------------------- Framework --------------------------\n");
+  if (ms) ot("CycloneRun\n");
+  else    ot("CycloneRun:\n");
+
+  ot("  stmdb sp!,{r4-r11,lr}\n");
+
+  ot("  mov r7,r0          ;@ r7 = Pointer to Cpu Context\n");
+  ot("                     ;@ r0-3 = Temporary registers\n");
+  ot("  ldrb r9,[r7,#0x46] ;@ r9 = Flags (NZCV)\n");
+  ot("  ldr r6,=JumpTab    ;@ r6 = Opcode Jump table\n");
+  ot("  ldr r5,[r7,#0x5c]  ;@ r5 = Cycles\n");
+  ot("  ldr r4,[r7,#0x40]  ;@ r4 = Current PC + Memory Base\n");
+  ot("                     ;@ r8 = Current Opcode\n");
+  ot("  mov r9,r9,lsl #28  ;@ r9 = Flags 0xf0000000, cpsr format\n");
+  ot("                     ;@ r10 = Source value / Memory Base\n");
+  ot("\n");
+  CheckInterrupt();
+  ot(";@ Check if interrupt used up all the cycles:\n");
+  ot("  subs r5,r5,#0\n");
+  ot("  blt CycloneEndNoBack\n");
+
+  OpFirst();
+  ltorg();
+  ot("\n");
+
+  ot(";@ We come back here after execution\n");
+  ot("CycloneEnd%s\n", ms?"":":");
+  ot("  sub r4,r4,#2\n");
+  ot("CycloneEndNoBack%s\n", ms?"":":");
+  ot("  mov r9,r9,lsr #28\n");
+  ot("  str r4,[r7,#0x40]  ;@ Save Current PC + Memory Base\n");
+  ot("  str r5,[r7,#0x5c]  ;@ Save Cycles\n");
+  ot("  strb r9,[r7,#0x46] ;@ Save Flags (NZCV)\n");
+  ot("  ldmia sp!,{r4-r11,pc}\n");
+  ot("\n");
+
+  ot(";@ DoInterrupt - r0=IRQ number\n");
+  ot("DoInterrupt%s\n", ms?"":":");
+  ot("\n");
+  ot("  ldrb r1,[r7,#0x44] ;@ Get SR high: T_S__III\n");
+  ot("  and r1,r1,#7 ;@ Get interrupt mask\n");
+  ot("  cmp r0,#6 ;@ irq>6 ?\n");
+  ot("  cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n");
+  ot("  movle pc,lr ;@ irq<=6 and mask, not allowed\n");
+  ot("\n");
+  ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+  ot("  mov r11,lr ;@ Preserve ARM return address\n");
+  ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");
+  OpPush32();
+  OpPushSr(1);
+  ot(";@ Get IRQ Vector address:\n");
+  ot("  ldrb r1,[r7,#0x47] ;@ IRQ\n");
+  ot("  mov r0,r1,asl #2\n");
+  ot("  add r0,r0,#0x60\n");
+  ot(";@ Read IRQ Vector:\n");
+  MemHandler(0,2);
+  ot("  add r0,r0,r10 ;@ r0 = Memory Base + New PC\n");
+  ot("  mov lr,pc\n");
+  ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
+  ot("  mov r4,r0\n");
+  ot("\n");
+  ot(";@ todo - swap OSP and A7 if not in Supervisor mode\n");
+  ot("  ldrb r0,[r7,#0x47] ;@ IRQ\n");
+  ot("  orr r0,r0,#0x20 ;@ Supervisor mode + IRQ number\n");
+  ot("  strb r0,[r7,#0x44] ;@ Put SR high\n");
+  ot("\n");
+  ot(";@ Clear irq:\n");
+  ot("  mov r0,#0\n");
+  ot("  strb r0,[r7,#0x47]\n");
+  ot("  subs r5,r5,#%d ;@ Subtract cycles\n",46);
+  ot("  mov pc,r11 ;@ Return\n");
+  ot("\n");
+
+  ot("Exception%s\n", ms?"":":");
+  ot("\n");
+  ot("  mov r11,lr ;@ Preserve ARM return address\n");
+  PrintException();
+  ot("  mov pc,r11 ;@ Return\n");
+  ot("\n");
+}
+
+// ---------------------------------------------------------------------------
+// Call Read(r0), Write(r0,r1) or Fetch(r0)
+// Trashes r0-r3
+int MemHandler(int type,int size)
+{
+  int func=0;
+  func=0x68+type*0xc+(size<<2); // Find correct offset
+
+  if (Debug&4) ot("  str r4,[r7,#0x40] ;@ Save PC\n");
+  if (Debug&3) ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
+
+  ot("  mov lr,pc\n");
+  ot("  ldr pc,[r7,#0x%x] ;@ Call ",func);
+
+  // Document what we are calling:
+  if (type==0) ot("read");
+  if (type==1) ot("write");
+  if (type==2) ot("fetch");
+
+  if (type==1) ot("%d(r0,r1)",8<<size);
+  else         ot("%d(r0)",   8<<size);
+  ot(" handler\n");
+
+  if (Debug&2) ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
+  return 0;
+}
+
+static void PrintOpcodes()
+{
+  int op=0;
+ 
+  printf("Creating Opcodes: [");
+
+  ot(";@ ---------------------------- Opcodes ---------------------------\n");
+
+  // Emit null opcode:
+  ot("Op____%s ;@ Called if an opcode is not recognised\n", ms?"":":");
+  OpStart(-1); Cycles=4; OpEnd(); //test
+
+  ot("  b CycloneEnd\n\n");
+
+  for (op=0;op<0x10000;op++)
+  {
+    if ((op&0xfff)==0) { printf("%x",op>>12); fflush(stdout); } // Update progress
+
+    OpAny(op);
+  }
+
+  ot("\n");
+
+  printf("]\n");
+}
+
+static void PrintJumpTable()
+{
+  int i=0,op=0,len=0;
+
+  ot(";@ -------------------------- Jump Table --------------------------\n");
+  ot("JumpTab%s\n", ms?"":":");
+
+  len=0xfffe; // Hmmm, armasm 2.50.8684 messes up with a 0x10000 long jump table
+  for (i=0;i<len;i++)
+  {
+    op=CyJump[i];
+
+    if ((i&7)==0) ot(ms?"  dcd ":"  .long ");
+    if (op<0) ot("Op____"); else ot("Op%.4x",op);
+    
+    if ((i&7)==7) ot(" ;@ %.4x\n",i-7);
+    else if (i+1<len) ot(",");
+  }
+
+  ot("\n");
+}
+
+static int CycloneMake()
+{
+  char *name="Cyclone.s";
+  
+  // Open the assembly file
+  if (ms) name="Cyclone.asm";
+  AsmFile=fopen(name,"wt"); if (AsmFile==NULL) return 1;
+  
+  printf("Making %s...\n",name);
+
+  ot("\n;@ Cyclone 68000 Emulator v%x.%.3x - Assembler Output\n\n",CycloneVer>>12,CycloneVer&0xfff);
+
+  ot(";@ This code is licensed under the GNU General Public License version 2.0 and the MAME License.\n");
+  ot(";@ You can choose the license that has the most advantages for you.\n\n");
+  ot(";@ SVN repository can be found at http://code.google.com/p/cyclone68000/\n\n");
+
+  CyJump=(int *)malloc(0x40000); if (CyJump==NULL) return 1;
+  memset(CyJump,0xff,0x40000); // Init to -1
+
+  if (ms)
+  {
+    ot("  area |.text|, code\n");
+    ot("  export CycloneRun\n");
+    ot("  export CycloneVer\n");
+    ot("\n");
+    ot("CycloneVer dcd 0x%.4x\n",CycloneVer);
+  }
+  else
+  {
+    ot("  .global CycloneRun\n");
+    ot("  .global CycloneVer\n");
+    ot("CycloneVer: .long 0x%.4x\n",CycloneVer);
+  }
+  ot("\n");
+
+  PrintFramework();
+  PrintOpcodes();
+  PrintJumpTable();
+
+  if (ms) ot("  END\n");
+
+  fclose(AsmFile); AsmFile=NULL;
+
+  printf("Assembling...\n");
+  // Assemble the file
+  if (ms) system("armasm Cyclone.asm");
+  else    system("as -o Cyclone.o Cyclone.s");
+  printf("Done!\n\n");
+
+  free(CyJump);
+  return 0;
+}
+
+int main()
+{
+  printf("\n  Cyclone 68000 Emulator v%x.%.3x - Core Creator\n\n",CycloneVer>>12,CycloneVer&0xfff);
+
+  // Make GAS and ARMASM versions
+  for (ms=0;ms<2;ms++) CycloneMake();
+  return 0;
+}
diff --git a/Cyclone/OpAny.cpp b/Cyclone/OpAny.cpp
new file mode 100644
index 0000000..9a149bb
--- /dev/null
+++ b/Cyclone/OpAny.cpp
@@ -0,0 +1,117 @@
+
+#include "app.h"
+
+static unsigned char OpData[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static unsigned short CPU_CALL OpRead16(unsigned int a)
+{
+  return (unsigned short)( (OpData[a&15]<<8) | OpData[(a+1)&15] );
+}
+
+// For opcode 'op' use handler 'use'
+void OpUse(int op,int use)
+{
+  char text[64]="";
+  CyJump[op]=use;
+
+  if (op!=use) return;
+
+  // Disassemble opcode
+  DisaPc=0;
+  DisaText=text;
+  DisaWord=OpRead16;
+
+  DisaGet();
+  ot(";@ ---------- [%.4x] %s uses Op%.4x ----------\n",op,text,use);
+}
+
+void OpFirst()
+{
+  ot("  ldrh r8,[r4],#2 ;@ Fetch first opcode\n");
+  ot("  ldr pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
+}
+
+void OpStart(int op)
+{
+  Cycles=0;
+  OpUse(op,op); // This opcode obviously uses this handler
+  ot("Op%.4x%s\n", op, ms?"":":");
+}
+
+void OpEnd()
+{
+  ot("  ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
+  ot("  subs r5,r5,#%d ;@ Subtract cycles\n",Cycles);
+  ot("  ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
+  ot("  b CycloneEnd\n");
+  ltorg();
+  ot("\n");
+}
+
+int OpBase(int op)
+{
+  int ea=op&0x3f; // Get Effective Address
+  if (ea<0x10) return op&~0xf; // Use 1 handler for d0-d7 and a0-a7
+  if (ea>=0x18 && ea<0x28 && (ea&7)==7) return op; // Specific handler for (a7)+ and -(a7)
+  if (ea<0x38) return op&~7;   // Use 1 handler for (a0)-(a7), etc...
+  return op;
+}
+
+// Get flags, trashes r2
+int OpGetFlags(int subtract,int xbit)
+{
+  ot("  mrs r9,cpsr ;@ r9=flags\n");
+
+  if (subtract) ot("  eor r9,r9,#0x20000000 ;@ Invert carry\n");
+
+  if (Accu&1) if (xbit)
+  {
+    ot("  mov r2,r9,lsr #28\n");
+    ot("  strb r2,[r7,#0x45] ;@ Save X bit\n");
+  }
+  return 0;
+}
+
+// -----------------------------------------------------------------
+
+void OpAny(int op)
+{
+  memset(OpData,0x33,sizeof(OpData));
+  OpData[0]=(unsigned char)(op>>8);
+  OpData[1]=(unsigned char)op;
+
+  if ((op&0xf100)==0x0000) OpArith(op);
+  if ((op&0xc000)==0x0000) OpMove(op);
+  if ((op&0xf5bf)==0x003c) OpArithSr(op); // Ori/Andi/Eori $nnnn,sr
+  if ((op&0xf100)==0x0100) OpBtstReg(op);
+  if ((op&0xff00)==0x0800) OpBtstImm(op);
+  if ((op&0xf900)==0x4000) OpNeg(op);
+  if ((op&0xf1c0)==0x41c0) OpLea(op);
+  if ((op&0xf9c0)==0x40c0) OpMoveSr(op);
+  if ((op&0xfff8)==0x4840) OpSwap(op);
+  if ((op&0xffc0)==0x4840) OpPea(op);
+  if ((op&0xffb8)==0x4880) OpExt(op);
+  if ((op&0xfb80)==0x4880) OpMovem(op);
+  if ((op&0xff00)==0x4a00) OpTst(op);
+  if ((op&0xfff0)==0x4e40) OpTrap(op);
+  if ((op&0xfff8)==0x4e50) OpLink(op);
+  if ((op&0xfff8)==0x4e58) OpUnlk(op);
+  if ((op&0xfff0)==0x4e60) OpMoveUsp(op);
+  if ((op&0xfff8)==0x4e70) Op4E70(op); // Reset/Rts etc
+  if ((op&0xff80)==0x4e80) OpJsr(op);
+  if ((op&0xf000)==0x5000) OpAddq(op);
+  if ((op&0xf0c0)==0x50c0) OpSet(op);
+  if ((op&0xf0f8)==0x50c8) OpDbra(op);
+  if ((op&0xf000)==0x6000) OpBranch(op);
+  if ((op&0xf100)==0x7000) OpMoveq(op);
+  if ((op&0xa000)==0x8000) OpArithReg(op); // Or/Sub/And/Add
+  if ((op&0xb1f0)==0x8100) OpAbcd(op);
+  if ((op&0xb0c0)==0x80c0) OpMul(op);
+  if ((op&0x90c0)==0x90c0) OpAritha(op);
+  if ((op&0xb138)==0x9100) OpAddx(op);
+  if ((op&0xf000)==0xb000) OpCmpEor(op);
+  if ((op&0xf130)==0xc100) OpExg(op);
+  if ((op&0xf000)==0xe000) OpAsr(op); // Asr/l/Ror/l etc
+  if ((op&0xf8c0)==0xe0c0) OpAsrEa(op);
+
+}
diff --git a/Cyclone/OpArith.cpp b/Cyclone/OpArith.cpp
new file mode 100644
index 0000000..db80147
--- /dev/null
+++ b/Cyclone/OpArith.cpp
@@ -0,0 +1,521 @@
+
+#include "app.h"
+
+// --------------------- Opcodes 0x0000+ ---------------------
+// Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 00aaaaaa
+int OpArith(int op)
+{
+  int type=0,size=0;
+  int sea=0,tea=0;
+  int use=0;
+
+  // Get source and target EA
+  type=(op>>9)&7; if (type==4 || type>=7) return 1;
+  size=(op>>6)&3; if (size>=3) return 1;
+  sea=   0x003c;
+  tea=op&0x003f;
+
+  // See if we can do this opcode:
+  if (EaCanRead(tea,size)==0) return 1;
+  if (type!=6 && EaCanWrite(tea)==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc(10,0x0000, sea,size);
+  EaRead(10,    10, sea,size,1);
+
+  EaCalc(11,0x003f, tea,size);
+  EaRead(11,     0, tea,size,1);
+
+  ot(";@ Do arithmetic:\n");
+
+  if (type==0) ot("  orr r1,r0,r10\n");
+  if (type==1) ot("  and r1,r0,r10\n");
+  if (type==2) ot("  subs r1,r0,r10 ;@ Defines NZCV\n");
+  if (type==3) ot("  adds r1,r0,r10 ;@ Defines NZCV\n");
+  if (type==5) ot("  eor r1,r0,r10\n");
+  if (type==6) ot("  cmp r0,r10 ;@ Defines NZCV\n");
+
+  if (type<2 || type==5) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5
+
+  if (type< 2) OpGetFlags(0,0); // Ori/And
+  if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit
+  if (type==3) OpGetFlags(0,1); // Add: X-bit
+  if (type==5) OpGetFlags(0,0); // Eor
+  if (type==6) OpGetFlags(1,0); // Cmp: Subtract
+  ot("\n");
+
+  if (type!=6)
+  {
+    EaWrite(11, 1, tea,size,1);
+  }
+
+  // Correct cycles:
+  if (type==6)
+  {
+    if (size>=2 && tea<0x10) Cycles+=2;
+  }
+  else
+  {
+    if (size>=2) Cycles+=4;
+    if (tea>=0x10) Cycles+=4;
+    if (Amatch && type==1 && size>=2 && tea<0x10) Cycles-=2;
+  }
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x5000+ ---------------------
+int OpAddq(int op)
+{
+  // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA)
+  int num=0,type=0,size=0,ea=0;
+  int use=0;
+  char count[16]="";
+  int shift=0;
+
+  num =(op>>9)&7; if (num==0) num=8;
+  type=(op>>8)&1;
+  size=(op>>6)&3; if (size>=3) return 1;
+  ea  = op&0x3f;
+
+  // See if we can do this opcode:
+  if (EaCanRead (ea,size)==0) return 1;
+  if (EaCanWrite(ea     )==0) return 1;
+
+  use=op; if (ea<0x38) use&=~7;
+  if ((ea&0x38)==0x08) { size=2; use&=~0xc0; } // Every addq #n,An is 32-bit
+
+  if (num!=8) use|=0x0e00; // If num is not 8, use same handler
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op);
+  Cycles=ea<8?4:8;
+  if (size>=2 && ea!=8) Cycles+=4;
+
+  EaCalc(10,0x003f, ea,size);
+  EaRead(10,     0, ea,size,1);
+
+  shift=32-(8<<size);
+
+  if (num!=8)
+  {
+    int lsr=9-shift;
+
+    if (lsr>=0) ot("  mov r2,r8,lsr #%d ;@ Get quick value\n", lsr);
+    else        ot("  mov r2,r8,lsl #%d ;@ Get quick value\n",-lsr);
+
+    ot("  and r2,r2,#0x%.4x\n",7<<shift);
+    ot("\n");
+    strcpy(count,"r2");
+  }
+
+  if (num==8) sprintf(count,"#0x%.4x",8<<shift);
+
+  if (type==0) ot("  adds r1,r0,%s\n",count);
+  if (type==1) ot("  subs r1,r0,%s\n",count);
+
+  if ((ea&0x38)!=0x08) OpGetFlags(type,1);
+  ot("\n");
+
+  EaWrite(10,     1, ea,size,1);
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x8000+ ---------------------
+// 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)
+int OpArithReg(int op)
+{
+  int use=0;
+  int type=0,size=0,dir=0,rea=0,ea=0;
+
+  type=(op>>12)&5;
+  rea =(op>> 9)&7;
+  dir =(op>> 8)&1;
+  size=(op>> 6)&3; if (size>=3) return 1;
+  ea  = op&0x3f;
+
+  if (dir && ea<0x10) return 1; // addx/subx opcode
+
+  // See if we can do this opcode:
+  if (dir==0 && EaCanWrite(rea)==0) return 1;
+  if (dir    && EaCanWrite( ea)==0) return 1;
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use same opcode for Dn
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  ot(";@ Get r10=EA r11=EA value\n");
+  EaCalc(10,0x003f, ea,size);
+  EaRead(10,    11, ea,size,1);
+  ot(";@ Get r0=Register r1=Register value\n");
+  EaCalc( 0,0x0e00,rea,size);
+  EaRead( 0,     1,rea,size,1);
+
+  ot(";@ Do arithmetic:\n");
+  if (type==0) ot("  orr  ");
+  if (type==1) ot("  subs ");
+  if (type==4) ot("  and  ");
+  if (type==5) ot("  adds ");
+  if (dir) ot("r1,r11,r1\n");
+  else     ot("r1,r1,r11\n");
+
+  if ((type&1)==0) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
+
+  OpGetFlags(type==1,type&1); // 1==subtract
+  ot("\n");
+
+  ot(";@ Save result:\n");
+  if (dir) EaWrite(10, 1, ea,size,1);
+  else     EaWrite( 0, 1,rea,size,1);
+
+  if (size==1 && ea>=0x10) Cycles+=4;
+  if (size>=2) { if (ea<0x10) Cycles+=4; else Cycles+=2; }
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x80c0+ ---------------------
+int OpMul(int op)
+{
+  // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA)
+  int type=0,rea=0,sign=0,ea=0;
+  int use=0;
+
+  type=(op>>14)&1; // div/mul
+  rea =(op>> 9)&7;
+  sign=(op>> 8)&1;
+  ea  = op&0x3f;
+
+  // See if we can do this opcode:
+  if (EaCanRead(ea,1)==0) return 1;
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use same for all registers
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=type?70:133;
+
+  EaCalc(10,0x003f, ea, 1);
+  EaRead(10,    10, ea, 1);
+
+  EaCalc (0,0x0e00,rea, 2);
+  EaRead (0,     2,rea, 2);
+
+  if (type==0)
+  {
+    ot("  cmp r10,#0\n");
+    ot("  moveq r10,#1 ;@ Divide by zero\n");
+    ot("\n");
+    
+    if (sign)
+    {
+      ot("  mov r11,#0 ;@ r11 = 1 if the result is negative\n");
+      ot("  eorlt r11,r11,#1\n");
+      ot("  rsblt r10,r10,#0 ;@ Make r10 positive\n");
+      ot("\n");
+      ot("  cmp r2,#0\n");
+      ot("  eorlt r11,r11,#1\n");
+      ot("  rsblt r2,r2,#0 ;@ Make r2 positive\n");
+      ot("\n");
+    }
+
+    ot(";@ Divide r2 by r10\n");
+    ot("  mov r3,#0\n");
+    ot("  mov r1,r10\n");
+    ot("\n");
+    ot(";@ Shift up divisor till it's just less than numerator\n");
+    ot("Shift%.4x%s\n",op,ms?"":":");
+    ot("  cmp r1,r2,lsr #1\n");
+    ot("  movls r1,r1,lsl #1\n");
+    ot("  bcc Shift%.4x\n",op);
+    ot("\n");
+
+    ot("Divide%.4x%s\n",op,ms?"":":");
+    ot("  cmp r2,r1\n");
+    ot("  adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n");
+    ot("  subcs r2,r2,r1\n");
+    ot("  teq r1,r10\n");
+    ot("  movne r1,r1,lsr #1\n");
+    ot("  bne Divide%.4x\n",op);
+    ot("\n");
+
+    if (sign)
+    {
+      ot("  tst r11,r11\n");
+      ot("  rsbne r3,r3,#0 ;@ Negate if result is negative\n");
+    }
+
+    ot("  mov r11,r2 ;@ Remainder\n");
+
+    ot("  adds r1,r3,#0 ;@ Defines NZ, clears CV\n");
+    OpGetFlags(0,0);
+
+    ot("  mov r1,r1,lsl #16 ;@ Clip to 16-bits\n");
+    ot("  mov r1,r1,lsr #16\n");
+    ot("  orr r1,r1,r11,lsl #16 ;@ Insert remainder\n");
+  }
+
+  if (type==1)
+  {
+    char *shift="asr";
+
+    ot(";@ Get 16-bit signs right:\n");
+    if (sign==0) { ot("  mov r10,r10,lsl #16\n"); shift="lsr"; }
+    ot("  mov r2,r2,lsl #16\n");
+
+    if (sign==0) ot("  mov r10,r10,lsr #16\n");
+    ot("  mov r2,r2,%s #16\n",shift);
+    ot("\n");
+
+    ot("  mul r1,r2,r10\n");
+    ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
+    OpGetFlags(0,0);
+
+    if (Amatch && ea==0x3c) Cycles-=4;
+  }
+  ot("\n");
+
+  EaWrite(0,     1,rea, 2);
+
+
+  OpEnd();
+
+  return 0;
+}
+
+// Get X Bit into carry - trashes r2
+static int GetXBit(int subtract)
+{
+  ot(";@ Get X bit:\n");
+  ot("  ldrb r2,[r7,#0x45]\n");
+  if (subtract) ot("  mvn r2,r2,lsl #28 ;@ Invert it\n");
+  else          ot("  mov r2,r2,lsl #28\n");
+  ot("  msr cpsr_flg,r2 ;@ Get into Carry\n");
+  ot("\n");
+  return 0;
+}
+
+// --------------------- Opcodes 0x8100+ ---------------------
+// 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad)
+int OpAbcd(int op)
+{
+  int use=0;
+  int type=0,sea=0,addr=0,dea=0;
+  
+  type=(op>>14)&1;
+  dea =(op>> 9)&7;
+  addr=(op>> 3)&1;
+  sea = op     &7;
+
+  if (addr) { sea|=0x20; dea|=0x20; }
+
+  use=op&~0x0e07; // Use same opcode for all registers
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=6;
+
+  EaCalc( 0,0x0007, sea,0);
+  EaRead( 0,    10, sea,0,1);
+  EaCalc(11,0x0e00, dea,0);
+  EaRead(11,     1, dea,0,1);
+
+  ot("  ldrb r2,[r7,#0x45] ;@ Get X bit\n");
+  ot("  tst r2,#2\n");
+  ot("  addne r10,r10,#0x01000000 ;@ Add carry bit\n");
+
+  if (type)
+  {
+    ot(";@ Add units into r2:\n");
+    ot("  and r2,r1, #0x0f000000\n");
+    ot("  and r0,r10,#0x0f000000\n");
+    ot("  add r2,r2,r0\n");
+    ot("  cmp r2,#0x0a000000\n");
+    ot("  addpl r1,r1,#0x06000000 ;@ Decimal adjust units\n");
+    ot("  add r1,r1,r10 ;@ Add BCD\n");
+    ot("  mov r0,r1,lsr #24\n");
+    ot("  cmp r0,#0xa0\n");
+    ot("  addpl r1,r1,#0x60000000 ;@ Decimal adjust tens\n");
+    OpGetFlags(0,1);
+  }
+  else
+  {
+    ot(";@ Sub units into r2:\n");
+    ot("  and r2,r1, #0x0f000000\n");
+    ot("  and r0,r10,#0x0f000000\n");
+    ot("  subs r2,r2,r0\n");
+    ot("  submi r1,r1,#0x06000000 ;@ Decimal adjust units\n");
+    ot("  subs r1,r1,r10 ;@ Subtract BCD\n");
+    ot("  submis r1,r1,#0x60000000 ;@ Decimal adjust tens\n");
+    OpGetFlags(1,1);
+  }
+  ot("\n");
+
+  EaWrite(11,     1, dea,0,1);
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x90c0+ ---------------------
+// Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA)
+int OpAritha(int op)
+{
+  int use=0;
+  int type=0,size=0,sea=0,dea=0;
+
+  // Suba/Cmpa/Adda/(invalid):
+  type=(op>>13)&3; if (type>=3) return 1;
+
+  size=(op>>8)&1; size++;
+  dea=(op>>9)&7; dea|=8; // Dest=An
+  sea=op&0x003f; // Source
+
+  // See if we can do this opcode:
+  if (EaCanRead(sea,size)==0) return 1;
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use same opcode for An
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+  EaCalc ( 0,0x003f, sea,size);
+  EaRead ( 0,    10, sea,size);
+
+  EaCalc ( 0,0x0e00, dea,2);
+  EaRead ( 0,     1, dea,2);
+
+  if (type==0) ot("  sub r1,r1,r10\n");
+  if (type==1) ot("  cmp r1,r10 ;@ Defines NZCV\n");
+  if (type==1) OpGetFlags(1,0); // Get Cmp flags
+  if (type==2) ot("  add r1,r1,r10\n");
+  ot("\n");
+  
+  EaWrite( 0,     1, dea,2);
+
+  if (Amatch && sea==0x3c) Cycles-=size<2?4:8; // Correct?
+  if (size>=2) { if (sea<0x10) Cycles+=4; else Cycles+=2; }
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x9100+ ---------------------
+// Emit a Subx/Addx opcode, 1t01ddd1 zz000sss addx.z Ds,Dd
+int OpAddx(int op)
+{
+  int use=0;
+  int type=0,size=0,dea=0,sea=0;
+
+  type=(op>>12)&5;
+  dea =(op>> 9)&7;
+  size=(op>> 6)&3; if (size>=3) return 1;
+  sea = op&0x3f;
+
+  // See if we can do this opcode:
+  if (EaCanRead(sea,size)==0) return 1;
+  if (EaCanWrite(dea)==0) return 1;
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use same opcode for Dn
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=8;
+
+  ot(";@ Get r10=EA r11=EA value\n");
+  EaCalc( 0,0x003f,sea,size);
+  EaRead( 0,    11,sea,size,1);
+  ot(";@ Get r0=Register r1=Register value\n");
+  EaCalc( 0,0x0e00,dea,size);
+  EaRead( 0,     1,dea,size,1);
+
+  ot(";@ Do arithmetic:\n");
+  GetXBit(type==1);
+
+  if (type==5 && size<2)
+  {
+    ot(";@ Make sure the carry bit will tip the balance:\n");
+    if (size==0) ot("  ldr r2,=0x00ffffff\n");
+    else         ot("  ldr r2,=0x0000ffff\n");
+    ot("  orr r11,r11,r2\n");
+    ot("\n");
+  }
+
+  if (type==1) ot("  sbcs r1,r1,r11\n");
+  if (type==5) ot("  adcs r1,r1,r11\n");
+  OpGetFlags(type==1,1); // subtract
+  ot("\n");
+
+  ot(";@ Save result:\n");
+  EaWrite( 0, 1, dea,size,1);
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0xb000+ ---------------------
+// Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea)
+int OpCmpEor(int op)
+{
+  int rea=0,eor=0;
+  int size=0,ea=0,use=0;
+
+  // Get EA and register EA
+  rea=(op>>9)&7;
+  eor=(op>>8)&1;
+  size=(op>>6)&3; if (size>=3) return 1;
+  ea=op&0x3f;
+
+  // See if we can do this opcode:
+  if (EaCanRead(ea,size)==0) return 1;
+  if (eor && EaCanWrite(ea)==0) return 1;
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use 1 handler for register d0-7
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=eor?8:4;
+
+  ot(";@ Get EA into r10 and value into r0:\n");
+  EaCalc (10,0x003f,  ea,size);
+  EaRead (10,     0,  ea,size,1);
+
+  ot(";@ Get register operand into r1:\n");
+  EaCalc (1 ,0x0e00, rea,size);
+  EaRead (1,      1, rea,size,1);
+
+  ot(";@ Do arithmetic:\n");
+  if (eor==0) ot("  cmp r1,r0\n");
+  if (eor)
+  {
+    ot("  eor r1,r0,r1\n");
+    ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
+  }
+
+  OpGetFlags(eor==0,0); // Cmp like subtract
+  ot("\n");
+
+  if (size>=2) Cycles+=4; // Correct?
+  if (ea==0x3c) Cycles-=4;
+
+  if (eor) EaWrite(10, 1,ea,size,1);
+
+  OpEnd();
+  return 0;
+}
+
diff --git a/Cyclone/OpBranch.cpp b/Cyclone/OpBranch.cpp
new file mode 100644
index 0000000..0fef71d
--- /dev/null
+++ b/Cyclone/OpBranch.cpp
@@ -0,0 +1,376 @@
+
+#include "app.h"
+
+static void CheckPc()
+{
+  ot(";@ Check Memory Base+pc (r4)\n");
+  ot("  add lr,pc,#4\n");
+  ot("  mov r0,r4\n");
+  ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
+  ot("  mov r4,r0\n");
+  ot("\n");
+}
+
+// Push 32-bit value in r1 - trashes r0-r3
+void OpPush32()
+{
+  ot(";@ Push r1 onto stack\n");
+  ot("  ldr r0,[r7,#0x3c]\n");
+  ot("  sub r0,r0,#4 ;@ Predecrement A7\n");
+  ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
+  MemHandler(1,2);
+  ot("\n");
+}
+
+// Push SR - trashes r0-r3
+void OpPushSr(int high)
+{
+  ot(";@ Push SR:\n");
+  OpFlagsToReg(high);
+  ot("  ldr r0,[r7,#0x3c]\n");
+  ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
+  ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
+  MemHandler(1,1);
+  ot("\n");
+}
+
+// Pop SR - trashes r0-r3
+static void PopSr(int high)
+{
+  ot(";@ Pop SR:\n");
+  ot("  ldr r0,[r7,#0x3c]\n");
+  ot("  add r1,r0,#2 ;@ Postincrement A7\n");
+  ot("  str r1,[r7,#0x3c] ;@ Save A7\n");
+  MemHandler(0,1);
+  ot("\n");
+  OpRegToFlags(high);
+}
+
+// Pop PC - assumes r10=Memory Base - trashes r0-r3
+static void PopPc()
+{
+  ot(";@ Pop PC:\n");
+  ot("  ldr r0,[r7,#0x3c]\n");
+  ot("  add r1,r0,#4 ;@ Postincrement A7\n");
+  ot("  str r1,[r7,#0x3c] ;@ Save A7\n");
+  MemHandler(0,2);
+  ot("  add r4,r0,r10 ;@ r4=Memory Base+PC\n");
+  ot("\n");
+  CheckPc();
+}
+
+int OpTrap(int op)
+{
+  int use=0;
+
+  use=op&~0xf;
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(use);
+  ot("  and r0,r8,#0xf ;@ Get trap number\n");
+  ot("  orr r0,r0,#0x20\n");
+  ot("  mov r0,r0,asl #2\n");
+  ot("  str r0,[r7,#0x50] ;@ Save Exception Vector\n");
+  ot("  bl Exception\n");
+  ot("\n");
+
+  Cycles=38; OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4e50+ ---------------------
+int OpLink(int op)
+{
+  int use=0;
+
+  use=op&~7;
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(use);
+
+  ot(";@ Get An\n");
+  EaCalc(10, 7, 8, 2);
+  EaRead(10, 1, 8, 2, 1);
+
+  ot("  ldr r0,[r7,#0x3c] ;@ Get A7\n");
+  ot("  sub r0,r0,#4 ;@ A7-=4\n");
+  ot("  mov r11,r0\n");
+  ot("\n");
+  
+  ot(";@ Write An to Stack\n");
+  MemHandler(1,2);
+
+  ot(";@ Save to An\n");
+  EaWrite(10,11, 8, 2, 1);
+
+  ot(";@ Get offset:\n");
+  EaCalc(0,0,0x3c,1);
+  EaRead(0,0,0x3c,1);
+
+  ot("  add r11,r11,r0 ;@ Add offset to A7\n");
+  ot("  str r11,[r7,#0x3c]\n");
+  ot("\n");
+
+  Cycles=16;
+  OpEnd();
+  return 0;
+}
+
+// --------------------- Opcodes 0x4e58+ ---------------------
+int OpUnlk(int op)
+{
+  int use=0;
+
+  use=op&~7;
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(use);
+
+  ot(";@ Get An\n");
+  EaCalc(10, 7, 8, 2);
+  EaRead(10, 0, 8, 2, 1);
+
+  ot("  add r11,r0,#4 ;@ A7+=4\n");
+  ot("\n");
+  ot(";@ Pop An from stack:\n");
+  MemHandler(0,2);
+  ot("\n");
+  ot("  str r11,[r7,#0x3c] ;@ Save A7\n");
+  ot("\n");
+  ot(";@ An = value from stack:\n");
+  EaWrite(10, 0, 8, 2, 1);
+  
+  Cycles=12;
+  OpEnd();
+  return 0;
+}
+
+// --------------------- Opcodes 0x4e70+ ---------------------
+int Op4E70(int op)
+{
+  int type=0;
+
+  type=op&7;
+  // 01001110 01110ttt, reset/nop/stop/rte/rtd/rts/trapv/rtr
+  if (type==1) { OpStart(op); Cycles=4; OpEnd(); return 0; } // nop
+
+  if (type==3 || type==7) // rte/rtr
+  {
+    OpStart(op); Cycles=20;
+    PopSr(type==3);
+    ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+    PopPc();
+    if (type==3) CheckInterrupt();
+    OpEnd();
+    return 0;
+  }
+
+  if (type==5) // rts
+  {
+    OpStart(op); Cycles=16;
+    ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+    PopPc();
+    OpEnd();
+    return 0;
+  }
+
+  return 1;
+}
+
+// --------------------- Opcodes 0x4e80+ ---------------------
+// Emit a Jsr/Jmp opcode, 01001110 1mEEEeee
+int OpJsr(int op)
+{
+  int use=0;
+  int sea=0;
+
+  sea=op&0x003f;
+
+  // See if we can do this opcode:
+  if (EaCanRead(sea,-1)==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=14; // Correct?
+
+  ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+  ot("\n");
+  EaCalc(0,0x003f,sea,0);
+
+  ot(";@ Jump - Get new PC from r0\n");
+  if (op&0x40)
+  {
+    // Jmp - Get new PC from r0
+    ot("  add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");
+    ot("\n");
+  }
+  else
+  {
+    ot(";@ Jsr - Push old PC first\n");
+    ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");
+    ot("  add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");
+    ot("\n");
+    OpPush32();
+
+    Cycles+=8;
+  }
+
+  if (Amatch && sea==0x10) Cycles-=2; // (An) Correct?
+
+  CheckPc();
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x50c8+ ---------------------
+
+// ARM version of 68000 condition codes:
+static char *Cond[16]=
+{
+  "",  "",  "hi","ls","cc","cs","ne","eq",
+  "vc","vs","pl","mi","ge","lt","gt","le"
+};
+
+// Emit a Dbra opcode, 0101cccc 11001nnn vv
+int OpDbra(int op)
+{
+  int use=0;
+  int cc=0;
+
+  use=op&~7; // Use same handler
+  cc=(op>>8)&15;
+  
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+  OpStart(op); Cycles=10;
+
+  ot(";@ Decrement Dn.w\n");
+  ot("  and r1,r8,#0x0007\n");
+  ot("  mov r1,r1,lsl #2\n");
+  ot("  ldrsh r0,[r7,r1]\n");
+  ot("  sub r0,r0,#1\n");
+  ot("  strh r0,[r7,r1]\n");
+  ot("\n");
+
+  if (cc>=2)
+  {
+    ot(";@ Is the condition true?\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
+    ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000\n");
+    ot(";@ If so, don't dbra\n");
+    ot("  b%s DbraEnd%.4x\n",Cond[cc],op);
+    ot("\n");
+  }
+
+  ot(";@ Check if Dn.w is -1\n");
+  ot("  cmps r0,#-1\n");
+  ot("  beq DbraEnd%.4x\n",op);
+  ot("\n");
+
+  ot(";@ Get Branch offset:\n");
+  ot("  ldrsh r0,[r4]\n");
+  ot("  add r4,r4,r0 ;@ r4 = New PC\n");
+  ot("\n");
+  OpEnd();
+  
+  ot("DbraEnd%.4x%s\n", op, ms?"":":");
+  Cycles+=2;
+  ot("  add r4,r4,#2 ;@ Skip branch offset\n");
+  ot("\n");
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x6000+ ---------------------
+// Emit a Branch opcode 0110cccc nn  (cccc=condition)
+int OpBranch(int op)
+{
+  int size=0,use=0;
+  int offset=0;
+  int cc=0;
+
+  offset=(char)(op&0xff);
+  cc=(op>>8)&15;
+
+  // Special offsets:
+  if (offset==0)  size=1;
+  if (offset==-1) size=2;
+
+  if (size) use=op; // 16-bit or 32-bit
+  else use=(op&0xff00)+1; // Use same opcode for all 8-bit branches
+
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+  OpStart(op); Cycles=10; // Assume branch taken
+
+  ot(";@ Get Branch offset:\n");
+  if (size)
+  {
+    EaCalc(0,0,0x3c,size);
+    EaRead(0,0,0x3c,size);
+    if (Amatch && size==1) Cycles-=4;
+  }
+
+  if (size==0) ot("  mov r0,r8,asl #24 ;@ Shift 8-bit signed offset up...\n\n");
+
+  if (cc>=2)
+  {
+    ot(";@ Is the condition true?\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
+    ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000\n");
+
+    if (size==0) ot("  mov r0,r0,asr #24 ;@ ...shift down\n\n");
+
+    ot("  b%s DontBranch%.4x\n",Cond[cc^1],op);
+
+    ot("\n");
+  }
+  else
+  {
+    if (size==0) ot("  mov r0,r0,asr #24 ;@ ...shift down\n\n");
+  }
+
+  ot(";@ Branch taken - Add on r0 to PC\n");
+
+  if (cc==1)
+  {
+    ot(";@ Bsr - remember old PC\n");
+    ot("  ldr r10,[r7,#0x60] ;@ Get Memory base\n");
+    ot("  sub r1,r4,r10 ;@ r1 = Old PC\n");
+    ot("\n");
+    if (size) ot("  sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);
+    ot("  add r4,r4,r0 ;@ r4 = New PC\n");
+    ot("\n");
+    OpPush32();
+    Cycles+=8;
+  }
+  else
+  {
+    if (size) ot("  sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);
+    ot("  add r4,r4,r0 ;@ r4 = New PC\n");
+    ot("\n");
+  }
+
+  if (offset==0 || offset==-1)
+  {
+    ot(";@ Branch is quite far, so may be a good idea to check Memory Base+pc\n");
+    CheckPc();
+  }
+
+  OpEnd();
+
+  if (cc>=2)
+  {
+    ot("DontBranch%.4x%s\n", op, ms?"":":");
+    Cycles-=2; // Branch not taken
+    OpEnd();
+  }
+
+  return 0;
+}
+
diff --git a/Cyclone/OpLogic.cpp b/Cyclone/OpLogic.cpp
new file mode 100644
index 0000000..0ff2e3f
--- /dev/null
+++ b/Cyclone/OpLogic.cpp
@@ -0,0 +1,523 @@
+#include "app.h"
+
+// --------------------- Opcodes 0x0100+ ---------------------
+// Emit a Btst (Register) opcode 0000nnn1 00aaaaaa
+int OpBtstReg(int op)
+{
+  int use=0;
+  int type=0,sea=0,tea=0;
+  int size=0;
+
+  type=(op>>6)&3;
+  // Get source and target EA
+  sea=(op>>9)&7;
+  tea=op&0x003f;
+  if (tea<0x10) size=2; // For registers, 32-bits
+
+  if ((tea&0x38)==0x08) return 1; // movep
+
+  // See if we can do this opcode:
+  if (EaCanRead(tea,0)==0) return 1;
+  if (type>0)
+  {
+    if (EaCanWrite(tea)==0) return 1;
+  }
+
+  use=OpBase(op);
+  use&=~0x0e00; // Use same handler for all registers
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+  if (tea<0x10) Cycles+=2;
+  if (type>0) Cycles+=4;
+
+  ot("  mov r10,#1\n");
+
+  EaCalc (0,0x0e00,sea,0);
+  EaRead (0,     0,sea,0);
+  ot("  bic r9,r9,#0x40000000 ;@ Blank Z flag\n");
+  ot("  mov r10,r10,lsl r0 ;@ Make bit mask\n");
+  ot("\n");
+
+  EaCalc(11,0x003f,tea,size);
+  EaRead(11,     0,tea,size);
+  ot("  tst r0,r10 ;@ Do arithmetic\n");
+  ot("  orreq r9,r9,#0x40000000 ;@ Get Z flag\n");
+  ot("\n");
+
+  if (type>0)
+  {
+    if (type==1) ot("  eor r1,r0,r10 ;@ Toggle bit\n");
+    if (type==2) ot("  bic r1,r0,r10 ;@ Clear bit\n");
+    if (type==3) ot("  orr r1,r0,r10 ;@ Set bit\n");
+    ot("\n");
+    EaWrite(11,   1,tea,size);
+  }
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x0800+ ---------------------
+// Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn
+int OpBtstImm(int op)
+{
+  int type=0,sea=0,tea=0;
+  int use=0;
+  int size=0;
+
+  type=(op>>6)&3;
+  // Get source and target EA
+  sea=   0x003c;
+  tea=op&0x003f;
+  if (tea<0x10) size=2; // For registers, 32-bits
+
+  // See if we can do this opcode:
+  if (EaCanRead(tea,0)==0) return 1;
+  if (type>0)
+  {
+    if (EaCanWrite(tea)==0) return 1;
+  }
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+  if (type<3 && tea<0x10) Cycles+=2;
+  if (type>0) Cycles+=4;
+
+  ot("  mov r10,#1\n");
+  ot("\n");
+  EaCalc ( 0,0x0000,sea,0);
+  EaRead ( 0,     0,sea,0);
+  ot("  bic r9,r9,#0x40000000 ;@ Blank Z flag\n");
+  ot("  mov r10,r10,lsl r0 ;@ Make bit mask\n");
+  ot("\n");
+
+  EaCalc (11,0x003f,tea,size);
+  EaRead (11,     0,tea,size);
+  ot("  tst r0,r10 ;@ Do arithmetic\n");
+  ot("  orreq r9,r9,#0x40000000 ;@ Get Z flag\n");
+  ot("\n");
+
+  if (type>0)
+  {
+    if (type==1) ot("  eor r1,r0,r10 ;@ Toggle bit\n");
+    if (type==2) ot("  bic r1,r0,r10 ;@ Clear bit\n");
+    if (type==3) ot("  orr r1,r0,r10 ;@ Set bit\n");
+    ot("\n");
+    EaWrite(11,   1,tea,size);
+  }
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4000+ ---------------------
+int OpNeg(int op)
+{
+  // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA)
+  int type=0,size=0,ea=0,use=0;
+
+  type=(op>>9)&3;
+  ea  =op&0x003f;
+  size=(op>>6)&3; if (size>=3) return 1;
+
+  switch (type)
+  {
+    case 1: case 2: case 3: break;
+    default: return 1; // todo
+  }
+
+  // See if we can do this opcode:
+  if (EaCanRead (ea,size)==0) return 1;
+  if (EaCanWrite(ea     )==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=size<2?4:6;
+
+  EaCalc (10,0x003f,ea,size);
+
+  if (type!=1) EaRead (10,0,ea,size); // Don't need to read for 'clr'
+  if (type==1) ot("\n");
+
+  if (type==1)
+  {
+    ot(";@ Clear:\n");
+    ot("  mov r1,#0\n");
+    ot("  mov r9,#0x40000000 ;@ NZCV=0100\n");
+    ot("\n");
+  }
+
+  if (type==2)
+  {
+    ot(";@ Neg:\n");
+    ot("  rsbs r1,r0,#0\n");
+    OpGetFlags(1,1);
+    ot("\n");
+  }
+
+  if (type==3)
+  {
+    ot(";@ Not:\n");
+    ot("  mvn r1,r0\n");
+    ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
+    OpGetFlags(0,0);
+    ot("\n");
+  }
+
+  EaWrite(10,     1,ea,size);
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4840+ ---------------------
+// Swap, 01001000 01000nnn swap Dn
+int OpSwap(int op)
+{
+  int ea=0,use=0;
+
+  ea=op&7;
+  use=op&~0x0007; // Use same opcode for all An
+
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc (10,0x0007,ea,2);
+  EaRead (10,     0,ea,2);
+
+  ot("  mov r1,r0,ror #16\n");
+  ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
+  OpGetFlags(0,0);
+
+  EaWrite(10,     1,8,2);
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4a00+ ---------------------
+// Emit a Tst opcode, 01001010 xxeeeeee
+int OpTst(int op)
+{
+  int sea=0;
+  int size=0,use=0;
+
+  sea=op&0x003f;
+  size=(op>>6)&3; if (size>=3) return 1;
+
+  // See if we can do this opcode:
+  if (EaCanWrite(sea)==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc ( 0,0x003f,sea,size);
+  EaRead ( 0,     0,sea,size);
+
+  ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
+  ot("  mrs r9,cpsr ;@ r9=flags\n");
+  ot("\n");
+
+  OpEnd();
+  return 0;
+}
+
+// --------------------- Opcodes 0x4880+ ---------------------
+// Emit an Ext opcode, 01001000 1x000nnn
+int OpExt(int op)
+{
+  int ea=0;
+  int size=0,use=0;
+  int shift=0;
+
+  ea=op&0x0007;
+  size=(op>>6)&1;
+  shift=32-(8<<size);
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc (10,0x0007,ea,size+1);
+  EaRead (10,     0,ea,size+1);
+
+  ot("  mov r0,r0,asl #%d\n",shift);
+  ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
+  ot("  mrs r9,cpsr ;@ r9=flags\n");
+  ot("  mov r1,r0,asr #%d\n",shift);
+  ot("\n");
+
+  EaWrite(10,     1,ea,size+1);
+
+  OpEnd();
+  return 0;
+}
+
+// --------------------- Opcodes 0x50c0+ ---------------------
+// Emit a Set cc opcode, 0101cccc 11eeeeee
+int OpSet(int op)
+{
+  int cc=0,ea=0;
+  int size=0,use=0;
+  char *cond[16]=
+  {
+    "al","", "hi","ls","cc","cs","ne","eq",
+    "vc","vs","pl","mi","ge","lt","gt","le"
+  };
+
+  cc=(op>>8)&15;
+  ea=op&0x003f;
+
+  if ((ea&0x38)==0x08) return 1; // dbra, not scc
+  
+  // See if we can do this opcode:
+  if (EaCanWrite(ea)==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=8;
+
+  if (ea<0x10) Cycles=4;
+
+  ot("  mov r1,#0\n");
+
+  if (cc!=1)
+  {
+    ot(";@ Is the condition true?\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
+    ot("  msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
+    if ((cc&~1)==2) ot("  eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
+    ot("  mvn%s r1,r1\n",cond[cc]);
+  }
+
+  if (ea<0x10) ot("  sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]);
+  ot("\n");
+
+  EaCalc (0,0x003f, ea,size);
+  EaWrite(0,     1, ea,size);
+
+  OpEnd();
+  return 0;
+}
+
+// Emit a Asr/Lsr/Roxr/Ror opcode
+static int EmitAsr(int op,int type,int dir,int count,int size,int usereg)
+{
+  char pct[8]="";
+  int shift=32-(8<<size);
+
+  if (count>=1) sprintf(pct,"#%d",count); // Fixed count
+
+  if (count<0)
+  {
+    ot("  mov r2,r8,lsr #9 ;@ Get 'n'\n");
+    ot("  and r2,r2,#7\n\n"); strcpy(pct,"r2");
+  }
+
+  if (usereg)
+  {
+    ot(";@ Use Dn for count:\n");
+    ot("  ldr r2,[r7,r2,lsl #2]\n");
+    ot("  and r2,r2,#63\n");
+    ot("\n");
+  }
+
+  // Take 2*n cycles:
+  if (count<0) ot("  sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n");
+  else Cycles+=count<<1;
+
+  if (type<2)
+  {
+    // Asr/Lsr
+    if (dir==0 && size<2)
+    {
+      ot(";@ For shift right, also copy to lowest bits (to get carry bit):\n");
+      ot("  orr r0,r0,r0,lsr #%d\n",32-(8<<size));
+      ot("\n");
+    }
+
+    ot(";@ Shift register:\n");
+    if (type==0) ot("  movs r0,r0,%s %s\n",dir?"asl":"asr",pct);
+    if (type==1) ot("  movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);
+    OpGetFlags(0,1);
+    ot("\n");
+
+    if (size<2)
+    {
+      ot(";@ Check if result is zero:\n");
+      ot("  movs r2,r0,lsr #%d\n",shift);
+      ot("  orreq r9,r9,#0x40000000\n");
+      ot("\n");
+    }
+  }
+
+  // --------------------------------------
+  if (type==2)
+  {
+    // Roxr
+    int wide=8<<size;
+
+    if (shift) ot("  mov r0,r0,lsr #%d ;@ Shift down\n",shift);
+
+    ot(";@ Rotate register through X:\n");
+    if (strcmp("r2",pct)!=0) { ot("  mov r2,%s\n",pct); strcpy(pct,"r2"); } // Get into register
+
+    if (count!=8)
+    {
+      ot(";@ Reduce r2 until <0:\n");
+      ot("Reduce_%.4x%s\n",op,ms?"":":");
+      ot("  subs r2,r2,#%d\n",wide+1);
+      ot("  bpl Reduce_%.4x\n",op);
+      ot("  add r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);
+      ot("\n");
+    }
+
+    if (dir) ot("  rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);
+
+    ot(";@ Rotate bits:\n");
+    ot("  mov r3,r0,lsr r2 ;@ Get right part\n");
+    ot("  rsb r2,r2,#%d\n",wide+1);
+    ot("  movs r0,r0,lsl r2 ;@ Get left part\n");
+    ot("  orr r0,r3,r0 ;@ r0=Rotated value\n");
+
+    ot(";@ Insert X bit into r2-1:\n");
+    ot("  ldrb r3,[r7,#0x45]\n");
+    ot("  sub r2,r2,#1\n");
+    ot("  and r3,r3,#2\n");
+    ot("  mov r3,r3,lsr #1\n");
+    ot("  orr r0,r0,r3,lsl r2\n");
+    ot("\n");
+
+    if (shift) ot("  movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);
+    OpGetFlags(0,1);
+    ot("\n");
+  }
+
+  // --------------------------------------
+  if (type==3)
+  {
+    // Ror
+    if (size<2)
+    {
+      ot(";@ Mirror value in whole 32 bits:\n");
+      if (size<=0) ot("  orr r0,r0,r0,lsr #8\n");
+      if (size<=1) ot("  orr r0,r0,r0,lsr #16\n");
+      ot("\n");
+    }
+
+    ot(";@ Rotate register:\n");
+    if (count<0)
+    {
+      if (dir) ot("  rsb r2,%s,#32\n",pct);
+      ot("  movs r0,r0,ror %s\n",pct);
+    }
+    else
+    {
+      int ror=count;
+      if (dir) ror=32-ror;
+      if (ror&31) ot("  movs r0,r0,ror #%d\n",ror);
+    }
+
+    if (dir)
+    {
+      ot(";@ Get carry bit from bit 0:\n");
+      ot("  mov r9,#0\n");
+      ot("  ands r2,r0,#1\n");
+      ot("  orrne r9,r9,#0x20000000\n");
+    }
+    else
+    {
+      OpGetFlags(0,0);
+    }
+    ot("\n");
+
+  }
+  // --------------------------------------
+  
+  return 0;
+}
+
+// Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn
+// (ccc=count, d=direction xx=size extension, u=use reg for count, tt=type, nnn=register Dn)
+int OpAsr(int op)
+{
+  int ea=0,use=0;
+  int count=0,dir=0;
+  int size=0,usereg=0,type=0;
+
+  ea=0;
+  count =(op>>9)&7;
+  dir   =(op>>8)&1;
+  size  =(op>>6)&3;
+  if (size>=3) return 1; // todo Asr EA
+  usereg=(op>>5)&1;
+  type  =(op>>3)&3;
+
+  if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8
+
+  // Use the same opcode for target registers:
+  use=op&~0x0007;
+
+  // As long as count is not 8, use the same opcode for all shift counts::
+  if (usereg==0 && count!=8) { use|=0x0e00; count=-1; }
+  if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn
+
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=size<2?6:8;
+
+  EaCalc(10,0x0007, ea,size);
+  EaRead(10,     0, ea,size,1);
+
+  EmitAsr(op,type,dir,count, size,usereg);
+
+  EaWrite(10,    0, ea,size,1);
+
+  OpEnd();
+
+  return 0;
+}
+
+// Asr/l/Ror/l etc EA - 11100ttd 11eeeeee 
+int OpAsrEa(int op)
+{
+  int use=0,type=0,dir=0,ea=0,size=1;
+
+  type=(op>>9)&3;
+  dir =(op>>8)&1;
+  ea  = op&0x3f;
+
+  if (ea<0x10) return 1;
+  // See if we can do this opcode:
+  if (EaCanRead(ea,0)==0) return 1;
+  if (EaCanWrite(ea)==0) return 1;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=8;
+
+  EaCalc (10,0x003f,ea,size);
+  EaRead (10,     0,ea,size,1);
+
+  EmitAsr(op,type,dir,1, size,0);
+
+  ot(";@ Save shifted value back to EA:\n");
+  ot("  mov r1,r0\n");
+  EaWrite(10,     1,ea,size,1);
+
+  OpEnd();
+  return 0;
+}
diff --git a/Cyclone/OpMove.cpp b/Cyclone/OpMove.cpp
new file mode 100644
index 0000000..2a1b5fe
--- /dev/null
+++ b/Cyclone/OpMove.cpp
@@ -0,0 +1,454 @@
+
+#include "app.h"
+
+// --------------------- Opcodes 0x1000+ ---------------------
+// Emit a Move opcode, 00xxdddd ddssssss
+int OpMove(int op)
+{
+  int sea=0,tea=0;
+  int size=0,use=0;
+  int movea=0;
+
+  // Get source and target EA
+  sea = op&0x003f;
+  tea =(op&0x01c0)>>3;
+  tea|=(op&0x0e00)>>9;
+
+  if (tea>=8 && tea<0x10) movea=1;
+
+  // Find size extension
+  switch (op&0x3000)
+  {
+    default: return 1;
+    case 0x1000: size=0; break;
+    case 0x3000: size=1; break;
+    case 0x2000: size=2; break;
+  }
+
+  if (movea && size<1) return 1; // movea.b is invalid
+
+  // See if we can do this opcode:
+  if (EaCanRead (sea,size)==0) return 1;
+  if (EaCanWrite(tea     )==0) return 1;
+
+  use=OpBase(op);
+  if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7
+  
+  if (tea>=0x18 && tea<0x28 && (tea&7)==7) use|=0x0e00; // Specific handler for (a7)+ and -(a7)
+
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc(0,0x003f,sea,size);
+  EaRead(0,     0,sea,size);
+
+  ot("  adds r1,r0,#0 ;@ Defines NZ, clears CV\n");
+
+  if (movea==0)  ot("  mrs r9,cpsr ;@ r9=NZCV flags\n");
+  ot("\n");
+
+  if (movea) size=2; // movea always expands to 32-bits
+
+  EaCalc (0,0x0e00,tea,size);
+  EaWrite(0,     1,tea,size);
+
+  OpEnd();
+  return 0;
+}
+
+// --------------------- Opcodes 0x41c0+ ---------------------
+// Emit an Lea opcode, 0100nnn1 11aaaaaa
+int OpLea(int op)
+{
+  int use=0;
+  int sea=0,tea=0;
+
+  sea= op&0x003f;
+  tea=(op&0x0e00)>>9; tea|=8;
+
+  if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode:
+
+  use=OpBase(op);
+  use&=~0x0e00; // Also use 1 handler for target ?0-7
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  EaCalc (1,0x003f,sea,0); // Lea
+  EaCalc (0,0x0e00,tea,2);
+  EaWrite(0,     1,tea,2);
+
+  if (Amatch)
+  {
+    // Correct?
+         if (sea< 0x18) Cycles+=4;
+    else if (sea==0x30) Cycles+=12;
+    else Cycles+=8;
+  }
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x40c0+ ---------------------
+
+// Pack our flags into r1, in SR/CCR register format
+// trashes r0,r2
+void OpFlagsToReg(int high)
+{
+  ot("  mov r1,r9,lsr #28   ;@ ____NZCV\n");
+  ot("  eor r0,r1,r1,ror #1 ;@ Bit 0=C^V\n");
+  ot("  tst r0,#1           ;@ 1 if C!=V\n");
+  ot("  eorne r1,r1,#3      ;@ ____NZVC\n");
+  ot("\n");
+  ot("  ldrb r0,[r7,#0x45]  ;@ X bit\n");
+  if (high) ot("  ldrb r2,[r7,#0x44]  ;@ Include SR high\n");
+  ot("  and r0,r0,#0x02\n");
+  if (high) ot("  orr r1,r1,r2,lsl #8\n");
+  ot("  orr r1,r1,r0,lsl #3 ;@ ___XNZVC\n");
+  ot("\n");
+}
+
+// Convert SR/CRR register in r0 to our flags
+// trashes r0,r1
+void OpRegToFlags(int high)
+{
+  ot("  eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");
+  ot("  mov r2,r0,lsr #3    ;@ r2=___XN\n");
+  ot("  tst r1,#1           ;@ 1 if C!=V\n");
+  ot("  eorne r0,r0,#3      ;@ ___XNZCV\n");
+  ot("  strb r2,[r7,#0x45]  ;@ Store X bit\n");
+  ot("  mov r9,r0,lsl #28   ;@ r9=NZCV...\n");
+
+  if (high)
+  {
+    ot("  mov r0,r0,ror #8\n");
+    ot("  strb r0,[r7,#0x44] ;@ Store SR high\n");
+  }
+  ot("\n");
+}
+
+static void SuperCheck(int op)
+{
+  ot("  ldrb r0,[r7,#0x44] ;@ Get SR high\n");
+  ot("  tst r0,#0x20 ;@ Check we are in supervisor mode\n");
+  ot("  beq WrongMode%.4x ;@ No\n",op);
+  ot("\n");
+}
+
+static void SuperEnd(int op)
+{
+  ot("WrongMode%.4x%s\n",op,ms?"":":");
+  ot(";@ todo - cause an exception\n");
+  OpEnd();
+}
+
+// Move SR opcode, 01000tt0 11aaaaaa move to SR
+int OpMoveSr(int op)
+{
+  int type=0,ea=0;
+  int use=0,size=1;
+
+  type=(op>>9)&3;
+  ea=op&0x3f;
+
+  switch(type)
+  {
+    case 0: case 1:
+      if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode:
+    break;
+
+    default: return 1; // todo
+
+    case 2: case 3:
+      if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode:
+    break;
+  }
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op);
+       if (type==0) Cycles=8;
+  else if (type==1) Cycles=6;
+  else Cycles=12;
+
+  if (Amatch && ea==0x3c) Cycles-=4; // Correct?
+
+  if (type==0 || type==3) SuperCheck(op);
+
+  if (type==0 || type==1)
+  {
+    OpFlagsToReg(type==0);
+    EaCalc (0,0x003f,ea,size);
+    EaWrite(0,     1,ea,size);
+  }
+
+  if (type==2 || type==3)
+  {
+    EaCalc(0,0x003f,ea,size);
+    EaRead(0,     0,ea,size);
+    OpRegToFlags(type==3);
+    if (type==3) CheckInterrupt();
+  }
+
+  OpEnd();
+
+  if (type==0 || type==3) SuperEnd(op);
+
+  return 0;
+}
+
+
+// Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100
+int OpArithSr(int op)
+{
+  int type=0,ea=0;
+  int use=0,size=0;
+
+  type=(op>>9)&5; if (type==4) return 1;
+  size=(op>>6)&1;
+  ea=0x3c;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=16;
+
+  SuperCheck(op);
+
+  EaCalc(0,0x003f,ea,size);
+  EaRead(0,    10,ea,size);
+
+  OpFlagsToReg(size);
+  if (type==0) ot("  orr r0,r1,r10\n");
+  if (type==1) ot("  and r0,r1,r10\n");
+  if (type==5) ot("  eor r0,r1,r10\n");
+  OpRegToFlags(size);
+  if (size) CheckInterrupt();
+
+  OpEnd();
+  SuperEnd(op);
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4850+ ---------------------
+// Emit an Pea opcode, 01001000 01aaaaaa
+int OpPea(int op)
+{
+  int use=0;
+  int ea=0;
+
+  ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode
+  if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode:
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=20;
+
+  EaCalc (1,0x003f, ea,0);
+  ot("\n");
+  ot("  ldr r0,[r7,#0x3c]\n");
+  ot("  sub r0,r0,#4 ;@ Predecrement A7\n");
+  ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
+  ot("\n");
+  MemHandler(1,2); // Write 32-bit
+  ot("\n");
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4880+ ---------------------
+// Emit a Movem opcode, 01001d00 1xeeeeee regmask
+int OpMovem(int op)
+{
+  int size=0,ea=0,cea=0,dir=0;
+  int use=0,decr=0,change=0;
+
+  size=((op>>6)&1)+1;
+  ea=op&0x003f;
+  dir=(op>>10)&1; // Direction
+
+  if (ea<0x10 || ea>0x39) return 1; // Invalid EA
+  if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1;
+  if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr
+
+  // See if we can do this opcode:
+  if (EaCanWrite(ea)==0) return 1;
+
+  cea=ea; if (change) cea=0x10;
+
+  use=OpBase(op);
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op);
+
+  ot("  stmdb sp!,{r9} ;@ Push r9\n");
+  ot("  ldrh r11,[r4],#2 ;@ r11=register mask\n");
+
+  ot("\n");
+  ot(";@ Get the address into r9:\n");
+  EaCalc(9,0x003f,cea,size);
+
+  ot(";@ r10=Register Index*4:\n");
+  if (decr) ot("  mov r10,#0x3c ;@ order reversed for -(An)\n");
+  else      ot("  mov r10,#0\n");
+  
+  ot("\n");
+  ot("MoreReg%.4x%s\n",op, ms?"":":");
+
+  ot("  tst r11,#1\n");
+  ot("  beq SkipReg%.4x\n",op);
+  ot("\n");
+
+  if (decr) ot("  sub r9,r9,#%d ;@ Pre-decrement address\n",1<<size);
+
+  if (dir)
+  {
+    ot("  ;@ Copy memory to register:\n",1<<size);
+    EaRead (9,0,ea,size);
+    ot("  str r0,[r7,r10] ;@ Save value into Dn/An\n");
+  }
+  else
+  {
+    ot("  ;@ Copy register to memory:\n",1<<size);
+    ot("  ldr r1,[r7,r10] ;@ Load value from Dn/An\n");
+    EaWrite(9,1,ea,size);
+  }
+
+  if (decr==0) ot("  add r9,r9,#%d ;@ Post-increment address\n",1<<size);
+
+  ot("  sub r5,r5,#%d ;@ Take some cycles\n",2<<size);
+  ot("\n");
+  ot("SkipReg%.4x%s\n",op, ms?"":":");
+  ot("  movs r11,r11,lsr #1;@ Shift mask:\n");
+  ot("  add r10,r10,#%d ;@ r10=Next Register\n",decr?-4:4);
+  ot("  bne MoreReg%.4x\n",op);
+  ot("\n");
+
+  if (change)
+  {
+    ot(";@ Write back address:\n");
+    EaCalc (0,0x0007,8|(ea&7),2);
+    EaWrite(0,     9,8|(ea&7),2);
+  }
+
+  ot("  ldmia sp!,{r9} ;@ Pop r9\n");
+  ot("\n");
+
+       if (ea<0x10) { }
+  else if (ea<0x18) Cycles=16; // (a0)
+  else if (ea<0x20) Cycles= 0; // (a0)+ ?
+  else if (ea<0x28) Cycles= 8; //-(a0)
+  else if (ea<0x30) Cycles=24; // ($3333,a0)
+  else if (ea<0x38) Cycles=28; // ($33,a0,d3.w*2)
+  else if (ea<0x39) Cycles=24; // $3333.w
+  else if (ea<0x3a) Cycles=28; // $33333333.l
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x4e60+ ---------------------
+// Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP
+int OpMoveUsp(int op)
+{
+  int use=0,dir=0;
+
+  dir=(op>>3)&1; // Direction
+  use=op&~0x0007; // Use same opcode for all An
+
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  ot("  ldrb r0,[r7,#0x44] ;@ Get SR\n");
+  ot("  tst r0,#0x20 ;@ Check we are in supervisor mode\n");
+  ot("  beq WrongMode%.4x ;@ No\n",op);
+  ot("\n");
+
+  if (dir)
+  {
+    EaCalc (0,0x0007,8,2);
+    ot("  ldr r1,[r7,#0x48] ;@ Get from USP\n\n");
+    EaWrite(0,     1,8,2);
+  }
+  else
+  {
+    EaCalc (0,0x0007,8,2);
+    EaRead (0,     0,8,2);
+    ot("  str r0,[r7,#0x48] ;@ Put in USP\n\n");
+  }
+    
+  OpEnd();
+
+  ot("WrongMode%.4x%s\n",op,ms?"":":");
+  ot(";@ todo - cause an exception\n");
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0x7000+ ---------------------
+// Emit a Move Quick opcode, 0111nnn0 dddddddd  moveq #dd,Dn
+int OpMoveq(int op)
+{
+  int use=0;
+
+  use=op&0xf100; // Use same opcode for all values
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=4;
+
+  ot("  movs r0,r8,asl #24\n");
+  ot("  and r1,r8,#0x0e00\n");
+  ot("  mov r0,r0,asr #24 ;@ Sign extended Quick value\n");
+  ot("  mrs r9,cpsr ;@ r9=NZ flags\n");
+  ot("  str r0,[r7,r1,lsr #7] ;@ Store into Dn\n");
+  ot("\n");
+
+  OpEnd();
+
+  return 0;
+}
+
+// --------------------- Opcodes 0xc140+ ---------------------
+// Emit a Exchange opcode:
+// 1100ttt1 01000sss  exg ds,dt
+// 1100ttt1 01001sss  exg as,at
+// 1100ttt1 10001sss  exg as,dt
+int OpExg(int op)
+{
+  int use=0,type=0;
+
+  type=op&0xf8;
+
+  if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode
+
+  use=op&0xf1f8; // Use same opcode for all values
+  if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
+
+  OpStart(op); Cycles=6;
+
+  ot("  and r10,r8,#0x0e00 ;@ Find T register\n");
+  ot("  and r11,r8,#0x000f ;@ Find S register\n");
+  if (type==0x48) ot("  orr r10,r10,#0x1000 ;@ T is an address register\n");
+  ot("\n");
+  ot("  ldr r0,[r7,r10,lsr #7] ;@ Get T\n");
+  ot("  ldr r1,[r7,r11,lsl #2] ;@ Get S\n");
+  ot("\n");
+  ot("  str r0,[r7,r11,lsl #2] ;@ T->S\n");
+  ot("  str r1,[r7,r10,lsr #7] ;@ S->T\n");  
+  ot("\n");
+
+  OpEnd();
+  
+  return 0;
+}
diff --git a/Cyclone/app.h b/Cyclone/app.h
new file mode 100644
index 0000000..f4795cc
--- /dev/null
+++ b/Cyclone/app.h
@@ -0,0 +1,85 @@
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Disa.c
+#include "../Pico/Disa.h"
+
+// Ea.cpp
+int EaCalc(int a,int mask,int ea,int size);
+int EaRead(int a,int v,int ea,int size,int top=0);
+int EaCanRead(int ea,int size);
+int EaWrite(int a,int v,int ea,int size,int top=0);
+int EaCanWrite(int ea);
+
+// Main.cpp
+extern int *CyJump; // Jump table
+extern int ms; // If non-zero, output in Microsoft ARMASM format
+extern char *Narm[4]; // Normal ARM Extensions for operand sizes 0,1,2
+extern char *Sarm[4]; // Sign-extend ARM Extensions for operand sizes 0,1,2
+extern int Cycles; // Current cycles for opcode
+extern int Amatch; // If one, try to match A68K timing
+extern int Accu; // Accuracy
+extern int Debug; // Debug info
+void ot(char *format, ...);
+void ltorg();
+void CheckInterrupt();
+int MemHandler(int type,int size);
+
+// OpAny.cpp
+int OpGetFlags(int subtract,int xbit);
+void OpUse(int op,int use);
+void OpFirst();
+void OpStart(int op);
+void OpEnd();
+int OpBase(int op);
+void OpAny(int op);
+
+//----------------------
+// OpArith.cpp
+int OpArith(int op);
+int OpLea(int op);
+int OpAddq(int op);
+int OpArithReg(int op);
+int OpMul(int op);
+int OpAbcd(int op);
+int OpAritha(int op);
+int OpAddx(int op);
+int OpCmpEor(int op);
+
+// OpBranch.cpp
+void OpPush32();
+void OpPushSr(int high);
+int OpTrap(int op);
+int OpLink(int op);
+int OpUnlk(int op);
+int Op4E70(int op);
+int OpJsr(int op);
+int OpBranch(int op);
+int OpDbra(int op);
+
+// OpLogic.cpp
+int OpBtstReg(int op);
+int OpBtstImm(int op);
+int OpNeg(int op);
+int OpSwap(int op);
+int OpTst(int op);
+int OpExt(int op);
+int OpSet(int op);
+int OpAsr(int op);
+int OpAsrEa(int op);
+
+// OpMove.cpp
+int OpMove(int op);
+int OpLea(int op);
+void OpFlagsToReg(int high);
+void OpRegToFlags(int high);
+int OpMoveSr(int op);
+int OpArithSr(int op);
+int OpPea(int op);
+int OpMovem(int op);
+int OpMoveq(int op);
+int OpMoveUsp(int op);
+int OpExg(int op);
diff --git a/Pico/Disa.c b/Pico/Disa.c
new file mode 100644
index 0000000..dbab233
--- /dev/null
+++ b/Pico/Disa.c
@@ -0,0 +1,846 @@
+
+// Dave's Disa 68000 Disassembler
+#ifndef __GNUC__
+#pragma warning(disable:4115)
+#endif
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <string.h>
+#include "Disa.h"
+
+unsigned int DisaPc=0;
+char *DisaText=NULL; // Text buffer to write in
+static char Tasm[]="bwl?";
+static char Comment[64]="";
+unsigned short (CPU_CALL *DisaWord)(unsigned int a)=NULL;
+
+static unsigned int DisaLong(unsigned int a)
+{
+  unsigned int d=0;
+  if (DisaWord==NULL) return d;
+
+  d= DisaWord(a)<<16;
+  d|=DisaWord(a+2)&0xffff;
+  return d;
+}
+
+// Get text version of the effective address
+int DisaGetEa(char *t,int ea,int size)
+{
+  ea&=0x3f; t[0]=0;
+  if ((ea&0x38)==0x00) { sprintf(t,"d%d",ea  ); return 0; }    // 000rrr
+  if ((ea&0x38)==0x08) { sprintf(t,"a%d",ea&7); return 0; }    // 001rrr
+  if ((ea&0x38)==0x10) { sprintf(t,"(a%d)",ea&7); return 0; }  // 010rrr
+  if ((ea&0x38)==0x18) { sprintf(t,"(a%d)+",ea&7); return 0; } // 011rrr
+  if ((ea&0x38)==0x20) { sprintf(t,"-(a%d)",ea&7); return 0; } // 100rrr
+  if ((ea&0x38)==0x28) { sprintf(t,"($%x,a%d)",DisaWord(DisaPc)&0xffff,ea&7); DisaPc+=2; return 0; } // 101rrr
+
+  if ((ea&0x38)==0x30)
+  {
+    // 110nnn - An + Disp + D/An
+    int areg=0,ext=0,off=0,da=0,reg=0,wol=0,scale=0;
+    ext=DisaWord(DisaPc)&0xffff;
+    
+    areg=ea&7;
+    off=ext&0xff;    da =ext&0x8000?'a':'d';
+    reg=(ext>>12)&7; wol=ext&0x0800?'l':'w';
+    scale=1<<((ext>>9)&3);
+
+    if (scale<2) sprintf(t,"($%x,a%d,%c%d.%c)",   off,areg,da,reg,wol);
+    else         sprintf(t,"($%x,a%d,%c%d.%c*%d)",off,areg,da,reg,wol,scale); // 68020
+
+    DisaPc+=2;
+    return 0;
+  }
+
+  if (ea==0x38) { sprintf(t,"$%x.w",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0; } // 111000 - Absolute short
+  if (ea==0x39) { sprintf(t,"$%x.l",DisaLong(DisaPc));        DisaPc+=4; return 0; } // 111001 - Absolute long
+
+  if (ea==0x3a)
+  {
+    // 111010 - PC Relative
+    int ext=DisaWord(DisaPc)&0xffff;
+    sprintf(t,"($%x,pc)",ext);
+    sprintf(Comment,"; =%x",DisaPc+(short)ext); // Comment where pc+ext is
+    DisaPc+=2;
+    return 0;
+  }
+
+  if (ea==0x3b)
+  {
+    // 111011 - PC Relative + D/An
+    int ext=0,off=0,da=0,reg=0,wol=0,scale=0;
+    ext=DisaWord(DisaPc)&0xffff;
+    
+    off=ext&0xff;    da =ext&0x8000?'a':'d';
+    reg=(ext>>12)&7; wol=ext&0x0800?'l':'w';
+    scale=1<<((ext>>9)&3);
+
+    if (scale<2) sprintf(t,"($%x,pc,%c%d.%c)",   off,da,reg,wol);
+    else         sprintf(t,"($%x,pc,%c%d.%c*%d)",off,da,reg,wol,scale); // 68020
+
+    sprintf(Comment,"; =%x",DisaPc+(char)off); // Comment where pc+ext is
+    DisaPc+=2;
+    return 0;
+  }
+
+  if (ea==0x3c)
+  {
+    // 111100 - Immediate
+    switch (size)
+    {
+      case 0: sprintf(t,"#$%x",DisaWord(DisaPc)&0x00ff); DisaPc+=2; return 0;
+      case 1: sprintf(t,"#$%x",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0;
+      case 2: sprintf(t,"#$%x",DisaLong(DisaPc)       ); DisaPc+=4; return 0;
+    }
+    return 1;
+  }
+
+// Unknown effective address
+  sprintf(t,"ea=(%d%d%d %d%d%d)",
+    (ea>>5)&1,(ea>>4)&1,(ea>>3)&1,
+    (ea>>2)&1,(ea>>1)&1, ea    &1);
+  return 1;
+}
+
+static void GetOffset(char *text)
+{
+  int off=(short)DisaWord(DisaPc); DisaPc+=2;
+
+  if (off<0) sprintf(text,"-$%x",-off);
+  else       sprintf(text,"$%x",  off);
+}
+
+// ================ Opcodes 0x0000+ ================
+static int DisaArithImm(int op)
+{
+  // Or/And/Sub/Add/Eor/Cmp Immediate 0000ttt0 xxDDDddd (tt=type, xx=size extension, DDDddd=Dest ea)
+  int dea=0;
+  char seat[64]="",deat[64]="";
+  int type=0,size=0;
+  char *arith[8]={"or","and","sub","add","?","eor","cmp","?"};
+
+  type=(op>>9)&7; if (type==4 || type>=7) return 1;
+  size=(op>>6)&3; if (size>=3) return 1;
+  dea=op&0x3f; if (dea==0x3c) return 1;
+
+  DisaGetEa(seat,0x3c,size);
+  DisaGetEa(deat,dea, size);
+
+  sprintf(DisaText,"%si.%c %s, %s",arith[type],Tasm[size],seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0x0108+ ================
+static int DisaMovep(int op)
+{
+  // movep.x (Aa),Dn - 0000nnn1 dx001aaa  nn
+  int dn=0,dir=0,size=0,an=0;
+  char offset[32]="";
+
+  dn  =(op>>9)&7;
+  dir =(op>>7)&1;
+  size=(op>>6)&1; size++;
+  an  = op    &7;
+
+  GetOffset(offset);
+  if (dir) sprintf(DisaText,"movep.%c d%d, (%s,a%d)",Tasm[size],dn,offset,an);
+  else     sprintf(DisaText,"movep.%c (%s,a%d), d%d",Tasm[size],offset,an,dn);
+
+  return 0;
+}
+
+// ================ Opcodes 0x007c+ ================
+static int DisaArithSr(int op)
+{
+  // Ori/Andi/Eori $nnnn,sr 0000t0tx 0s111100
+  char *opcode[6]={"ori","andi","","","","eori"};
+  char seat[64]="";
+  int type=0,size=0;
+
+  type=(op>>9)&5;
+  size=(op>>6)&1;
+
+  DisaGetEa(seat,0x3c,size);
+  sprintf(DisaText,"%s.%c %s, %s", opcode[type], Tasm[size], seat, size?"sr":"ccr");
+
+  return 0;
+}
+
+// ================ Opcodes 0x0100+ ================
+static int DisaBtstReg(int op)
+{
+  // Btst/Bchg/Bclr/Bset 0000nnn1 tteeeeee (nn=reg number, eeeeee=Dest ea)
+  int type=0;
+  int sea=0,dea=0;
+  char seat[64]="",deat[64]="";
+  char *opcode[4]={"btst","bchg","bclr","bset"};
+
+  sea =(op>>9)&7;
+  type=(op>>6)&3;
+  dea=  op&0x3f;
+
+  if ((dea&0x38)==0x08) return 1; // movep
+  DisaGetEa(seat,sea,0);
+  DisaGetEa(deat,dea,0);
+
+  sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0x0800+ ================
+static int DisaBtstImm(int op)
+{
+  // Btst/Bchg/Bclr/Bset 00001000 tteeeeee 00 nn (eeeeee=ea, nn=bit number)
+  int type=0;
+  char seat[64]="",deat[64]="";
+  char *opcode[4]={"btst","bchg","bclr","bset"};
+
+  type=(op>>6)&3;
+  DisaGetEa(seat,   0x3c,0);
+  DisaGetEa(deat,op&0x3f,0);
+
+  sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0x1000+ ================
+static int DisaMove(int op)
+{
+  // Move 00xxdddD DDssssss (xx=size extension, ssssss=Source EA, DDDddd=Dest ea)
+  int sea=0,dea=0;
+  char inst[64]="",seat[64]="",deat[64]="";
+  char *movea="";
+  int size=0;
+
+  if ((op&0x01c0)==0x0040) movea="a"; // See if it's a movea opcode
+
+  // Find size extension
+  switch (op&0x3000)
+  {
+    case 0x1000: size=0; break;
+    case 0x3000: size=1; break;
+    case 0x2000: size=2; break;
+    default: return 1;
+  }
+
+  sea = op&0x003f;
+  DisaGetEa(seat,sea,size);
+  
+  dea =(op&0x01c0)>>3;
+  dea|=(op&0x0e00)>>9;
+  DisaGetEa(deat,dea,size);
+
+  sprintf(inst,"move%s.%c",movea,Tasm[size]);
+  sprintf(DisaText,"%s %s, %s",inst,seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0x4000+ ================
+static int DisaNeg(int op)
+{
+  // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA)
+  char eat[64]="";
+  int type=0,size=0;
+  char *opcode[4]={"negx","clr","neg","not"};
+
+  type=(op>>9)&3;
+  size=(op>>6)&3; if (size>=3) return 1;
+  DisaGetEa(eat,op&0x3f,size);
+
+  sprintf(DisaText,"%s.%c %s",opcode[type],Tasm[size],eat);
+  return 0;
+}
+
+// ================ Opcodes 0x40c0+ ================
+static int DisaMoveSr(int op)
+{
+  // 01000tt0 11eeeeee (tt=type, xx=size, eeeeee=EA)
+  int type=0,ea=0;
+  char eat[64]="";
+
+  type=(op>>9)&3;
+  ea=op&0x3f;
+  DisaGetEa(eat,ea,1);
+
+  switch (type)
+  {
+    default: sprintf(DisaText,"move sr, %s", eat); break;
+    case 1:  sprintf(DisaText,"move ccr, %s",eat); break;
+    case 2:  sprintf(DisaText,"move %s, ccr",eat); break;
+    case 3:  sprintf(DisaText,"move %s, sr", eat); break;
+  }
+  return 0;
+}
+
+// ================ Opcodes 0x41c0+ ================
+static int DisaLea(int op)
+{
+  // Lea 0100nnn1 11eeeeee (eeeeee=ea)
+  int sea=0,dea=0;
+  char seat[64]="",deat[64]="";
+
+  sea=op&0x003f;
+  DisaGetEa(seat,sea,0);
+
+  dea=(op>>9)&7; dea|=8;
+  DisaGetEa(deat,dea,2);
+
+  sprintf(DisaText,"lea %s, %s",seat,deat);
+  return 0;
+}
+
+static int MakeRegList(char *list,int mask,int ea)
+{
+  int reverse=0,i=0,low=0,len=0;
+
+  if ((ea&0x38)==0x20) reverse=1; // -(An), bitfield is reversed
+
+  mask&=0xffff; list[0]=0;
+
+  for (i=0;i<17;i++)
+  {
+    int bit=0;
+    
+    // Mask off bit i:
+    if (reverse) bit=0x8000>>i; else bit=1<<i;
+    bit&=mask;
+
+    if (bit==0 || i==8)
+    {
+      // low to i-1 are a continuous section, add it:
+      char add[16]="";
+      int ad=low&8?'a':'d';
+      if (low==i-1) sprintf(add,"%c%d/",     ad,low&7);
+      if (low< i-1) sprintf(add,"%c%d-%c%d/",ad,low&7, ad,(i-1)&7);
+      strcat(list,add);
+
+      low=i; // Next section
+    }
+
+    if (bit==0) low=i+1;
+  }
+
+  // Knock off trailing '/'
+  len=strlen(list);
+  if (len>0) if (list[len-1]=='/') list[len-1]=0; 
+  return 0;
+}
+
+// ================ Opcodes 0x4840+ ================
+static int DisaSwap(int op)
+{
+  // Swap, 01001000 01000nnn swap Dn
+  sprintf(DisaText,"swap d%d",op&7);
+  return 0;
+}
+
+// ================ Opcodes 0x4850+ ================
+static int DisaPea(int op)
+{
+  // Pea 01001000 01eeeeee  (eeeeee=ea)  pea 
+  int ea=0;
+  char eat[64]="";
+
+  ea=op&0x003f; if (ea<0x10) return 1; // swap opcode
+  DisaGetEa(eat,ea,2);
+
+  sprintf(DisaText,"pea %s",eat);
+  return 0;
+}
+
+// ================ Opcodes 0x4880+ ================
+static int DisaExt(int op)
+{
+  // Ext 01001000 1x000nnn (x=size, eeeeee=EA)
+  char eat[64]="";
+  int size=0;
+
+  size=(op>>6)&1; size++;
+  DisaGetEa(eat,op&0x3f,size);
+
+  sprintf(DisaText,"ext.%c %s",Tasm[size],eat);
+  return 0;
+}
+
+// ================ Opcodes 0x4890+ ================
+static int DisaMovem(int op)
+{
+  // Movem 01001d00 1xeeeeee regmask  d=direction, x=size, eeeeee=EA
+  int dir=0,size=0;
+  int ea=0,mask=0;
+  char list[64]="",eat[64]="";
+
+  dir=(op>>10)&1;
+  size=((op>>6)&1)+1;
+  ea=op&0x3f; if (ea<0x10) return 1; // ext opcode
+
+  mask=DisaWord(DisaPc)&0xffff; DisaPc+=2;
+
+  MakeRegList(list,mask,ea); // Turn register mask into text
+  DisaGetEa(eat,ea,size);
+
+  if (dir) sprintf(DisaText,"movem.%c %s, %s",Tasm[size],eat,list);
+  else     sprintf(DisaText,"movem.%c %s, %s",Tasm[size],list,eat);
+  return 0;
+}
+
+// ================ Opcodes 0x4e40+ ================
+static int DisaTrap(int op)
+{
+  sprintf(DisaText,"trap #%d",op&0xf);
+  return 0;
+}
+
+// ================ Opcodes 0x4e50+ ================
+static int DisaLink(int op)
+{
+  // Link opcode, 01001110 01010nnn dd   link An,#offset
+  char eat[64]="";
+  char offset[32]="";
+
+  DisaGetEa(eat,(op&7)|8,0);
+  GetOffset(offset);
+
+  sprintf(DisaText,"link %s,#%s",eat,offset);
+
+  return 0;
+}
+
+// ================ Opcodes 0x4e58+ ================
+static int DisaUnlk(int op)
+{
+  // Link opcode, 01001110 01011nnn dd   unlk An
+  char eat[64]="";
+
+  DisaGetEa(eat,(op&7)|8,0);
+  sprintf(DisaText,"unlk %s",eat);
+
+  return 0;
+}
+
+// ================ Opcodes 0x4e60+ ================
+static int DisaMoveUsp(int op)
+{
+  // Move USP opcode, 01001110 0110dnnn move An to/from USP (d=direction)
+  int ea=0,dir=0;
+  char eat[64]="";
+
+  dir=(op>>3)&1;
+  ea=(op&7)|8;
+  DisaGetEa(eat,ea,0);
+
+  if (dir) sprintf(DisaText,"move usp, %s",eat);
+  else     sprintf(DisaText,"move %s, usp",eat);
+  return 0;
+}
+
+// ================ Opcodes 0x4e70+ ================
+static int Disa4E70(int op)
+{
+  char *inst[8]={"reset","nop","stop","rte","rtd","rts","trapv","rtr"};
+  int n=0;
+
+  n=op&7;
+
+  sprintf(DisaText,"%s",inst[n]);
+
+  //todo - 'stop' with 16 bit data
+  
+  return 0;
+}
+
+// ================ Opcodes 0x4a00+ ================
+static int DisaTst(int op)
+{
+  // Tst 01001010 xxeeeeee  (eeeeee=ea)
+  int ea=0;
+  char eat[64]="";
+  int size=0;
+
+  ea=op&0x003f;
+  DisaGetEa(eat,ea,0);
+  size=(op>>6)&3; if (size>=3) return 1;
+
+  sprintf(DisaText,"tst.%c %s",Tasm[size],eat);
+  return 0;
+}
+
+// ================ Opcodes 0x4e80+ ================
+static int DisaJsr(int op)
+{
+  // Jsr/Jmp 0100 1110 1mEE Eeee (eeeeee=ea m=1=jmp)
+  int sea=0;
+  char seat[64]="";
+
+  sea=op&0x003f;
+  DisaGetEa(seat,sea,0);
+
+  sprintf(DisaText,"j%s %s", op&0x40?"mp":"sr", seat);
+  return 0;
+}
+
+// ================ Opcodes 0x5000+ ================
+static int DisaAddq(int op)
+{
+  // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA)
+  int num=0,type=0,size=0,ea=0;
+  char eat[64]="";
+
+  num =(op>>9)&7; if (num==0) num=8;
+  type=(op>>8)&1;
+  size=(op>>6)&3; if (size>=3) return 1;
+  ea  = op&0x3f;
+
+  DisaGetEa(eat,ea,size);
+
+  sprintf(DisaText,"%s.%c #%d, %s",type?"subq":"addq",Tasm[size],num,eat);
+  return 0;
+}
+
+// ================ Opcodes 0x50c0+ ================
+static int DisaSet(int op)
+{
+  // 0101cccc 11eeeeee (sxx ea)
+  static char *cond[16]=
+  {"t" ,"f", "hi","ls","cc","cs","ne","eq",
+   "vc","vs","pl","mi","ge","lt","gt","le"};
+  char *cc="";
+  int ea=0;
+  char eat[64]="";
+
+  cc=cond[(op>>8)&0xf]; // Get condition code
+  ea=op&0x3f;
+  if ((ea&0x38)==0x08) return 1; // dbra, not scc
+
+  DisaGetEa(eat,ea,0);
+  sprintf(DisaText,"s%s %s",cc,eat);
+  return 0;
+}
+
+// ================ Opcodes 0x50c8+ ================
+static int DisaDbra(int op)
+{
+  // 0101cccc 11001nnn offset  (dbra/dbxx Rn,offset)
+  int dea=0; char deat[64]="";
+  int pc=0,Offset=0;
+
+  static char *BraCode[16]=
+  {"bt" ,"bra","bhi","bls","bcc","bcs","bne","beq",
+   "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"};
+  char *Bra="";
+
+  dea=op&7;
+  DisaGetEa(deat,dea,2);
+
+  // Get condition code
+  Bra=BraCode[(op>>8)&0xf];
+
+  // Get offset
+  pc=DisaPc;
+  Offset=(short)DisaWord(DisaPc); DisaPc+=2;
+
+  sprintf(DisaText,"d%s %s, %x",Bra,deat,pc+Offset);
+  return 0;
+}
+
+// ================ Opcodes 0x6000+ ================
+static int DisaBranch(int op)
+{
+  // Branch 0110cccc nn  (cccc=condition)
+  int pc=0,Offset=0;
+
+  static char *BraCode[16]=
+  {"bra","bsr","bhi","bls","bcc","bcs","bne","beq",
+   "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"};
+  char *Bra="";
+
+  // Get condition code
+  Bra=BraCode[(op>>8)&0x0f];
+
+  // Get offset
+  pc=DisaPc;
+  Offset=(char)(op&0xff);
+       if (Offset== 0) { Offset=(short)DisaWord(DisaPc); DisaPc+=2; }
+  else if (Offset==-1) { Offset=       DisaLong(DisaPc); DisaPc+=4; }
+
+  sprintf(DisaText,"%s %x",Bra,pc+Offset);
+  return 0;
+}
+
+// ================ Opcodes 0x7000+ ================
+static int DisaMoveq(int op)
+{
+  // Moveq 0111rrr0 nn (rrr=Dest register, nn=data)
+
+  int dea=0; char deat[64]="";
+  char *inst="moveq";
+  int val=0;
+
+  dea=(op>>9)&7;
+  DisaGetEa(deat,dea,2);
+
+  val=(char)(op&0xff);
+  sprintf(DisaText,"%s #$%x, %s",inst,val,deat);
+  return 0;
+}
+
+// ================ Opcodes 0x8000+ ================
+static int DisaArithReg(int op)
+{
+  // 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)
+  int type=0,size=0,dir=0,rea=0,ea=0;
+  char reat[64]="",eat[64]="";
+  char *opcode[]={"or","sub","","","and","add"};
+
+  type=(op>>12)&5;
+  rea =(op>> 9)&7;
+  dir =(op>> 8)&1;
+  size=(op>> 6)&3; if (size>=3) return 1;
+  ea  = op&0x3f;
+
+  if (dir && ea<0x10) return 1; // addx opcode
+
+  DisaGetEa(reat,rea,size);
+  DisaGetEa( eat, ea,size);
+
+  if (dir) sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],reat,eat);
+  else     sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],eat,reat);
+  return 0;
+}
+
+// ================ Opcodes 0x8100+ ================
+static int DisaAbcd(int op)
+{
+  // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad)
+  int type=0;
+  int dn=0,addr=0,sn=0;
+  char *opcode[]={"sbcd","abcd"};
+
+  type=(op>>14)&1;
+  dn  =(op>> 9)&7;
+  addr=(op>> 3)&1;
+  sn  = op     &7;
+
+  if (addr) sprintf(DisaText,"%s -(a%d), -(a%d)",opcode[type],sn,dn);
+  else      sprintf(DisaText,"%s d%d, d%d",       opcode[type],sn,dn);
+
+  return 0;
+}
+
+// ================ Opcodes 0x80c0+ ================
+static int DisaMul(int op)
+{
+  // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA)
+  int type=0,rea=0,sign=0,ea=0,size=1;
+  char reat[64]="",eat[64]="";
+  char *opcode[2]={"div","mul"};
+
+  type=(op>>14)&1; // div/mul
+  rea =(op>> 9)&7;
+  sign=(op>> 8)&1;
+  ea  = op&0x3f;
+
+  DisaGetEa(reat,rea,size);
+  DisaGetEa( eat, ea,size);
+
+  sprintf(DisaText,"%s%c.%c %s, %s",opcode[type],sign?'s':'u',Tasm[size],eat,reat);
+  return 0;
+}
+
+// ================ Opcodes 0x90c0+ ================
+static int DisaAritha(int op)
+{
+  // Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA)
+  int type=0,size=0,sea=0,dea=0;
+  char seat[64]="",deat[64]="";
+  char *aritha[4]={"suba","cmpa","adda",""};
+
+  type=(op>>13)&3; if (type>=3) return 1;
+  size=(op>>8)&1; size++;
+  dea =(op>>9)&7; dea|=8; // Dest=An
+  sea = op&0x003f; // Source
+
+  DisaGetEa(seat,sea,size);
+  DisaGetEa(deat,dea,size);
+
+  sprintf(DisaText,"%s.%c %s, %s",aritha[type],Tasm[size],seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0xb000+ ================
+static int DisaCmpEor(int op)
+{
+  // Cmp/Eor 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea)
+  char reat[64]="",eat[64]="";
+  int type=0,size=0;
+
+  type=(op>>8)&1;
+  size=(op>>6)&3; if (size>=3) return 1; // cmpa opcode
+  if ((op&0xf138)==0xb108) return 1; // cmpm opcode
+
+  DisaGetEa(reat,(op>>9)&7,size);
+  DisaGetEa(eat,  op&0x3f, size);
+
+  if (type) sprintf(DisaText,"eor.%c %s, %s",Tasm[size],reat,eat);
+  else      sprintf(DisaText,"cmp.%c %s, %s",Tasm[size],eat,reat);
+  return 0;
+}
+
+// ================ Opcodes 0xb108+ ================
+static int DisaCmpm(int op)
+{
+  // Cmpm  1011ddd1 xx001sss
+  int type=0,size=0,dea=0,sea=0;
+  char deat[64]="",seat[64]="";
+
+  type=(op>>12)&5;
+  dea =(op>> 9)&7; dea|=8;
+  size=(op>> 6)&3; if (size>=3) return 1;
+  sea  = op&0x3f;
+
+  DisaGetEa(deat,dea,size);
+  DisaGetEa(seat,sea,size);
+
+  sprintf(DisaText,"cmpm.%c (%s)+, (%s)+",Tasm[size],seat,deat);
+
+  return 0;
+}
+
+// ================ Opcodes 0xc140+ ================
+// 1100ttt1 01000sss  exg ds,dt
+// 1100ttt1 01001sss  exg as,at
+// 1100ttt1 10001sss  exg as,dt
+static int DisaExg(int op)
+{
+  int tr=0,type=0,sr=0;
+
+  tr  =(op>>9)&7;
+  type= op&0xf8;
+  sr  = op&7;
+
+       if (type==0x40) sprintf(DisaText,"exg d%d, d%d",sr,tr);
+  else if (type==0x48) sprintf(DisaText,"exg a%d, a%d",sr,tr);
+  else if (type==0x88) sprintf(DisaText,"exg a%d, d%d",sr,tr);
+  else return 1;
+
+  return 0;
+}
+
+// ================ Opcodes 0xd100+ ================
+static int DisaAddx(int op)
+{
+  // 1t01ddd1 xx000sss addx
+  int type=0,size=0,dea=0,sea=0;
+  char deat[64]="",seat[64]="";
+  char *opcode[6]={"","subx","","","","addx"};
+
+  type=(op>>12)&5;
+  dea =(op>> 9)&7;
+  size=(op>> 6)&3; if (size>=3) return 1;
+  sea  = op&0x3f;
+
+  DisaGetEa(deat,dea,size);
+  DisaGetEa(seat,sea,size);
+
+  sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],seat,deat);
+  return 0;
+}
+
+// ================ Opcodes 0xe000+ ================
+static char *AsrName[4]={"as","ls","rox","ro"};
+static int DisaAsr(int op)
+{
+  // Asr/l/Ror/l etc - 1110cccd xxuttnnn
+  // (ccc=count, d=direction xx=size extension, u=use reg for count, tt=type, nnn=register Dn)
+  int count=0,dir=0,size=0,usereg=0,type=0,num=0;
+
+  count =(op>>9)&7;
+  dir   =(op>>8)&1;
+  size  =(op>>6)&3; if (size>=3) return 1; // todo Asr EA
+  usereg=(op>>5)&1;
+  type  =(op>>3)&3;
+  num   = op    &7; // Register number
+
+  if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8
+
+  sprintf(DisaText,"%s%c.%c %c%d, d%d",
+    AsrName[type], dir?'l':'r', Tasm[size],
+    usereg?'d':'#', count, num);
+  return 0;
+}
+
+static int DisaAsrEa(int op)
+{
+  // Asr/l/Ror/l etc EA - 11100ttd 11eeeeee 
+  int type=0,dir=0,size=1;
+  char eat[64]="";
+
+  type=(op>>9)&3;
+  dir =(op>>8)&1;
+  DisaGetEa(eat,op&0x3f,size);
+
+  sprintf(DisaText,"%s%c.w %s", AsrName[type], dir?'l':'r', eat);
+  return 0;
+}
+
+// =================================================================
+
+static int TryOp(int op)
+{
+  if ((op&0xf100)==0x0000) DisaArithImm(op); // Ori/And/Sub/Add/Eor/Cmp Immediate
+  if ((op&0xf5bf)==0x003c) DisaArithSr(op); // Ori/Andi/Eori $nnnn,sr
+  if ((op&0xf100)==0x0100) DisaBtstReg(op);
+  if ((op&0xf138)==0x0108) DisaMovep(op);
+  if ((op&0xff00)==0x0800) DisaBtstImm(op); // Btst/Bchg/Bclr/Bset
+  if ((op&0xc000)==0x0000) DisaMove(op);
+  if ((op&0xf900)==0x4000) DisaNeg(op); // Negx/Clr/Neg/Not
+  if ((op&0xf1c0)==0x41c0) DisaLea(op);
+  if ((op&0xf9c0)==0x40c0) DisaMoveSr(op);
+  if ((op&0xfff8)==0x4840) DisaSwap(op);
+  if ((op&0xffc0)==0x4840) DisaPea(op);
+  if ((op&0xffb8)==0x4880) DisaExt(op);
+  if ((op&0xfb80)==0x4880) DisaMovem(op);
+  if ((op&0xff00)==0x4a00) DisaTst(op);
+  if ((op&0xfff0)==0x4e40) DisaTrap(op);
+  if ((op&0xfff8)==0x4e50) DisaLink(op);
+  if ((op&0xfff8)==0x4e58) DisaUnlk(op);
+  if ((op&0xfff0)==0x4e60) DisaMoveUsp(op);
+  if ((op&0xfff8)==0x4e70) Disa4E70(op);
+  if ((op&0xff80)==0x4e80) DisaJsr(op);
+  if ((op&0xf000)==0x5000) DisaAddq(op);
+  if ((op&0xf0c0)==0x50c0) DisaSet(op);
+  if ((op&0xf0f8)==0x50c8) DisaDbra(op);
+  if ((op&0xf000)==0x6000) DisaBranch(op);
+  if ((op&0xa000)==0x8000) DisaArithReg(op); // Or/Sub/And/Add
+  if ((op&0xb1f0)==0x8100) DisaAbcd(op);
+  if ((op&0xb130)==0x9100) DisaAddx(op);
+  if ((op&0xb0c0)==0x80c0) DisaMul(op);
+  if ((op&0xf100)==0x7000) DisaMoveq(op);
+  if ((op&0x90c0)==0x90c0) DisaAritha(op);
+  if ((op&0xf000)==0xb000) DisaCmpEor(op);
+  if ((op&0xf138)==0xb108) DisaCmpm(op);
+  if ((op&0xf130)==0xc100) DisaExg(op);
+  if ((op&0xf000)==0xe000) DisaAsr(op);
+  if ((op&0xf8c0)==0xe0c0) DisaAsrEa(op);
+
+  // Unknown opcoode
+  return 0;
+}
+
+int DisaGet()
+{
+  int op=0;
+  if (DisaWord==NULL) return 1;
+
+  Comment[0]=0;
+  DisaText[0]=0; // Assume opcode unknown
+
+  op=DisaWord(DisaPc)&0xffff; DisaPc+=2;
+  TryOp(op);
+  strcat(DisaText,Comment);
+
+  // Unknown opcoode
+  return 0;
+}
diff --git a/Pico/Disa.h b/Pico/Disa.h
new file mode 100644
index 0000000..af10eb5
--- /dev/null
+++ b/Pico/Disa.h
@@ -0,0 +1,20 @@
+
+// Dave's Disa 68000 Disassembler
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CPU_CALL
+
+extern unsigned int DisaPc;
+extern char *DisaText; // Text buffer to write in
+
+extern unsigned short (CPU_CALL *DisaWord)(unsigned int a);
+int DisaGetEa(char *t,int ea,int size);
+
+int DisaGet();
+
+#ifdef __cplusplus
+} // End of extern "C"
+#endif
diff --git a/test.txt b/test.txt
deleted file mode 100644
index 0fde866..0000000
--- a/test.txt
+++ /dev/null
@@ -1 +0,0 @@
-this is a test
-- 
2.39.5