--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+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
--- /dev/null
+\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
--- /dev/null
+ 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
--- /dev/null
+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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+#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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+\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
--- /dev/null
+\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
+++ /dev/null
-this is a test\r