first check-in of Cyclone 0.069 under GPLv2 and MAME License. Pico Disa.c/h included too
authoremudave <emudave@gmail.com>
Mon, 7 Feb 2011 22:06:07 +0000 (22:06 +0000)
committeremudave <emudave@gmail.com>
Mon, 7 Feb 2011 22:06:07 +0000 (22:06 +0000)
18 files changed:
Cyclone/Cyclone.dsp [new file with mode: 0644]
Cyclone/Cyclone.dsw [new file with mode: 0644]
Cyclone/Cyclone.h [new file with mode: 0644]
Cyclone/Cyclone.txt [new file with mode: 0644]
Cyclone/DoClean.bat [new file with mode: 0644]
Cyclone/Ea.cpp [new file with mode: 0644]
Cyclone/License-GPLv2.txt [new file with mode: 0644]
Cyclone/License.txt [new file with mode: 0644]
Cyclone/Main.cpp [new file with mode: 0644]
Cyclone/OpAny.cpp [new file with mode: 0644]
Cyclone/OpArith.cpp [new file with mode: 0644]
Cyclone/OpBranch.cpp [new file with mode: 0644]
Cyclone/OpLogic.cpp [new file with mode: 0644]
Cyclone/OpMove.cpp [new file with mode: 0644]
Cyclone/app.h [new file with mode: 0644]
Pico/Disa.c [new file with mode: 0644]
Pico/Disa.h [new file with mode: 0644]
test.txt [deleted file]

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