From 1b85bf1c2307c548a637f988eb69f615864f1685 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 22 Jun 2013 19:16:11 +0300 Subject: [PATCH] switch Cyclone to submodule on it's own git repo that version also has it's license clearly stated by fdave --- .gitmodules | 3 + cpu/Cyclone/Cyclone.h | 97 -- cpu/Cyclone/Cyclone.txt | 627 -------- cpu/Cyclone/Disa/Disa.c | 886 ----------- cpu/Cyclone/Disa/Disa.h | 18 - cpu/Cyclone/Ea.cpp | 493 ------- cpu/Cyclone/Main.cpp | 1298 ----------------- cpu/Cyclone/OpAny.cpp | 207 --- cpu/Cyclone/OpArith.cpp | 819 ----------- cpu/Cyclone/OpBranch.cpp | 517 ------- cpu/Cyclone/OpLogic.cpp | 702 --------- cpu/Cyclone/OpMove.cpp | 685 --------- cpu/Cyclone/app.h | 111 -- cpu/Cyclone/config.h | 182 --- cpu/Cyclone/config_mamegp2x.h | 44 - cpu/Cyclone/config_uae4all.h | 44 - cpu/Cyclone/epoc/crash_cyclone.bin | Bin 524 -> 0 bytes cpu/Cyclone/epoc/patchtable_symb.c | 150 -- cpu/Cyclone/epoc/patchtable_symb2.c | 133 -- cpu/Cyclone/epoc/readme.txt | 42 - cpu/Cyclone/proj/Makefile | 42 - cpu/Cyclone/proj/Makefile.win | 59 - cpu/Cyclone/proj/cyclone.dsp | 146 -- cpu/Cyclone/tests/crash_cyclone.bin | Bin 524 -> 0 bytes cpu/Cyclone/tests/test_abcd.bin | Bin 570 -> 0 bytes cpu/Cyclone/tests/test_cmpm.bin | Bin 618 -> 0 bytes cpu/Cyclone/tests/test_div.bin | Bin 604 -> 0 bytes cpu/Cyclone/tests/test_misc.bin | Bin 424960 -> 0 bytes cpu/Cyclone/tests/test_misc2_gen.c | 119 -- cpu/Cyclone/tests/test_negx.bin | Bin 542 -> 0 bytes cpu/Cyclone/tests/test_rol.bin | Bin 578 -> 0 bytes cpu/Cyclone/tests/test_shift.bin | Bin 582 -> 0 bytes cpu/Cyclone/tests/test_trace.bin | Bin 558 -> 0 bytes cpu/Cyclone/tests/test_trace.s | 140 -- cpu/Cyclone/tools/idle.h | 3 - cpu/Cyclone/tools/idle.s | 176 --- cpu/cyclone | 1 + .../config_pico.h => cyclone_config.h} | 0 38 files changed, 4 insertions(+), 7740 deletions(-) delete mode 100644 cpu/Cyclone/Cyclone.h delete mode 100644 cpu/Cyclone/Cyclone.txt delete mode 100644 cpu/Cyclone/Disa/Disa.c delete mode 100644 cpu/Cyclone/Disa/Disa.h delete mode 100644 cpu/Cyclone/Ea.cpp delete mode 100644 cpu/Cyclone/Main.cpp delete mode 100644 cpu/Cyclone/OpAny.cpp delete mode 100644 cpu/Cyclone/OpArith.cpp delete mode 100644 cpu/Cyclone/OpBranch.cpp delete mode 100644 cpu/Cyclone/OpLogic.cpp delete mode 100644 cpu/Cyclone/OpMove.cpp delete mode 100644 cpu/Cyclone/app.h delete mode 100644 cpu/Cyclone/config.h delete mode 100644 cpu/Cyclone/config_mamegp2x.h delete mode 100644 cpu/Cyclone/config_uae4all.h delete mode 100644 cpu/Cyclone/epoc/crash_cyclone.bin delete mode 100644 cpu/Cyclone/epoc/patchtable_symb.c delete mode 100644 cpu/Cyclone/epoc/patchtable_symb2.c delete mode 100644 cpu/Cyclone/epoc/readme.txt delete mode 100644 cpu/Cyclone/proj/Makefile delete mode 100644 cpu/Cyclone/proj/Makefile.win delete mode 100644 cpu/Cyclone/proj/cyclone.dsp delete mode 100755 cpu/Cyclone/tests/crash_cyclone.bin delete mode 100755 cpu/Cyclone/tests/test_abcd.bin delete mode 100755 cpu/Cyclone/tests/test_cmpm.bin delete mode 100755 cpu/Cyclone/tests/test_div.bin delete mode 100755 cpu/Cyclone/tests/test_misc.bin delete mode 100644 cpu/Cyclone/tests/test_misc2_gen.c delete mode 100755 cpu/Cyclone/tests/test_negx.bin delete mode 100755 cpu/Cyclone/tests/test_rol.bin delete mode 100755 cpu/Cyclone/tests/test_shift.bin delete mode 100755 cpu/Cyclone/tests/test_trace.bin delete mode 100644 cpu/Cyclone/tests/test_trace.s delete mode 100644 cpu/Cyclone/tools/idle.h delete mode 100644 cpu/Cyclone/tools/idle.s create mode 160000 cpu/cyclone rename cpu/{Cyclone/config_pico.h => cyclone_config.h} (100%) diff --git a/.gitmodules b/.gitmodules index c003620..b27d2a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "platform/libpicofe"] path = platform/libpicofe url = git://notaz.gp2x.de/~notaz/libpicofe.git +[submodule "cpu/cyclone"] + path = cpu/cyclone + url = git://notaz.gp2x.de/~notaz/cyclone68000.git diff --git a/cpu/Cyclone/Cyclone.h b/cpu/Cyclone/Cyclone.h deleted file mode 100644 index fc7695e..0000000 --- a/cpu/Cyclone/Cyclone.h +++ /dev/null @@ -1,97 +0,0 @@ - -// Cyclone 68000 Emulator - Header File - -// (c) Copyright 2004 Dave, All rights reserved. -// (c) 2005-2007 notaz -// Cyclone 68000 is free for non-commercial use. - -// For commercial use, separate licencing terms must be obtained. - - -#ifndef __CYCLONE_H__ -#define __CYCLONE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int CycloneVer; // Version number of library - -struct Cyclone -{ - unsigned int d[8]; // [r7,#0x00] - unsigned int a[8]; // [r7,#0x20] - unsigned int pc; // [r7,#0x40] Memory Base (.membase) + 68k PC - unsigned char srh; // [r7,#0x44] Status Register high (T_S__III) - unsigned char unused; // [r7,#0x45] Unused - unsigned char flags; // [r7,#0x46] Flags (ARM order: ____NZCV) [68k order is XNZVC] - unsigned char irq; // [r7,#0x47] IRQ level - unsigned int osp; // [r7,#0x48] Other Stack Pointer (USP/SSP) - unsigned int xc; // [r7,#0x4c] Extend flag (bit29: ??X? _) - unsigned int prev_pc; // [r7,#0x50] Set to start address of currently executed opcode + 2 (if enabled in config.h) - unsigned int jumptab; // [r7,#0x54] Jump table pointer - int state_flags; // [r7,#0x58] bit: 0: stopped state, 1: trace state, 2: activity bit, 3: addr error, 4: fatal halt - int cycles; // [r7,#0x5c] Number of cycles to execute - 1. Updates to cycles left after CycloneRun() - int membase; // [r7,#0x60] Memory Base (ARM address minus 68000 address) - unsigned int (*checkpc)(unsigned int pc); // [r7,#0x64] called to recalc Memory Base+pc - unsigned int (*read8 )(unsigned int a); // [r7,#0x68] - unsigned int (*read16 )(unsigned int a); // [r7,#0x6c] - unsigned int (*read32 )(unsigned int a); // [r7,#0x70] - void (*write8 )(unsigned int a,unsigned char d); // [r7,#0x74] - void (*write16)(unsigned int a,unsigned short d); // [r7,#0x78] - void (*write32)(unsigned int a,unsigned int d); // [r7,#0x7c] - unsigned int (*fetch8 )(unsigned int a); // [r7,#0x80] - unsigned int (*fetch16)(unsigned int a); // [r7,#0x84] - unsigned int (*fetch32)(unsigned int a); // [r7,#0x88] - int (*IrqCallback)(int int_level); // [r7,#0x8c] optional irq callback function, see config.h - void (*ResetCallback)(void); // [r7,#0x90] if enabled in config.h, calls this whenever RESET opcode is encountered. - int (*UnrecognizedCallback)(void); // [r7,#0x94] if enabled in config.h, calls this whenever unrecognized opcode is encountered. - unsigned int internal[6]; // [r7,#0x98] reserved for internal use, do not change. -}; - -// Initialize. Used only if Cyclone was compiled with compressed jumptable, see config.h -void CycloneInit(void); - -// Reset -void CycloneReset(struct Cyclone *pcy); - -// Run cyclone. Cycles should be specified in context (pcy->cycles) -void CycloneRun(struct Cyclone *pcy); - -// Utility functions to get and set SR -void CycloneSetSr(struct Cyclone *pcy, unsigned int sr); -unsigned int CycloneGetSr(const struct Cyclone *pcy); - -// Generates irq exception if needed (if pcy->irq > mask). -// Returns cycles used for exception if it was generated, 0 otherwise. -int CycloneFlushIrq(struct Cyclone *pcy); - -// Functions for saving and restoring state. -// CycloneUnpack() uses checkpc(), so it must be initialized. -// save_buffer must point to buffer of 128 (0x80) bytes of size. -void CyclonePack(const struct Cyclone *pcy, void *save_buffer); -void CycloneUnpack(struct Cyclone *pcy, const void *save_buffer); - -// genesis: if 1, switch to normal TAS handlers -void CycloneSetRealTAS(int use_real); - - -// These values are special return values for IrqCallback. - -// Causes an interrupt autovector (0x18 + interrupt level) to be taken. -// This happens in a real 68K if VPA or AVEC is asserted during an interrupt -// acknowledge cycle instead of DTACK (the most common situation). -#define CYCLONE_INT_ACK_AUTOVECTOR -1 - -// Causes the spurious interrupt vector (0x18) to be taken -// This happens in a real 68K if BERR is asserted during the interrupt -// acknowledge cycle (i.e. no devices responded to the acknowledge). -#define CYCLONE_INT_ACK_SPURIOUS -2 - - -#ifdef __cplusplus -} // End of extern "C" -#endif - -#endif // __CYCLONE_H__ - diff --git a/cpu/Cyclone/Cyclone.txt b/cpu/Cyclone/Cyclone.txt deleted file mode 100644 index 3397118..0000000 --- a/cpu/Cyclone/Cyclone.txt +++ /dev/null @@ -1,627 +0,0 @@ - - _____ __ - / ___/__ __ ____ / /___ ___ ___ ___________________ - / /__ / // // __// // _ \ / _ \/ -_) ___________________ - \___/ \_, / \__//_/ \___//_//_/\__/ ___________________ - /___/ - ___________________ ____ ___ ___ ___ ___ - ___________________ / __// _ \ / _ \ / _ \ / _ \ - ___________________ / _ \/ _ // // // // // // / - \___/\___/ \___/ \___/ \___/ - -___________________________________________________________________________ - - Cyclone 68000 (c) Copyright 2004 Dave. Free for non-commercial use - - Homepage: http://www.finalburn.com/ - Dave's e-mail: emudave(atsymbol)googlemail.com - Replace (atsymbol) with @ - - Additional coding and bugfixes done by notaz, 2005-2007 - Homepage: http://notaz.gp2x.de - e-mail: notasas(atsymbol)gmail.com -___________________________________________________________________________ - - -About ------ - -Cyclone 68000 is an emulator for the 68000 microprocessor, written in ARM 32-bit assembly. -It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret 68000 -code as fast as possible. It can emulate all 68000 instructions quite accurately, instruction -timing was synchronized with MAME's Musashi. Most 68k features are emulated (trace mode, -address errors), but prefetch is not emulated. - - -How to Compile --------------- - -Like Starscream and A68K, Cyclone uses a 'Core Creator' program which calculates and outputs -all possible 68000 Opcodes and a jump table into file called Cyclone.s or Cyclone.asm. -Only Cyclone.h and the mentioned .s or .asm file will be needed for your project, other files -are here to produce or test it. - -First unzip "Cyclone.zip" into a "Cyclone" directory. The next thing to do is to edit config.h -file to tune Cyclone for your project. There are lots of options in config.h, but all of them -are documented and have defaults. You should set a define value to 1 to enable option, and -to 0 to disable. - -After you are done with config.h, save it and compile Cyclone. If you are using Linux, Cygwin, -mingw or similar, you can simply cd to Cyclone/proj and type "make". If you are under Windows -and have Visual Studio installed, you can import cyclone.dsp in the proj/ directory and compile -it from there (this will produce cyclone.exe which you will have to run to get .s or .asm). -You can also use Microsoft command line compile tools by entering Cyclone/proj directory and -typing "nmake -f Makefile.win". Note that this step is done only to produce .s or .asm, and it -is done using native tools on your PC (not using cross-compiler or similar). - -The .s file is meant to be compiled with GNU assembler, and .asm with ARMASM.EXE -(the Microsoft ARM assembler). Once you have the file, you can add it to your -Makefile/project/whatever. - - -Adding to your project ----------------------- - -Compiling the .s or .asm (from previous step) for your target platform may require custom -build rules in your Makefile/project. - -If you use some gcc-based toolchain, you will need to add Cyclone.o to an object list in -the Makefile. GNU make will use "as" to build Cyclone.o from Cyclone.s by default, so -you may need to define correct cross-assembler by setting AS variable like this: - -AS = arm-linux-as - -This might be different in your case, basically it should be same prefix as for gcc. -You may also need to specify floating point type in your assembler flags for Cyclone.o -to link properly. This is done like this: - -ASFLAGS = -mfloat-abi=soft - -Note that Cyclone does not use floating points, this is just to make the linker happy. - - -If you are using Visual Studio, you may need to add "custom build step", which creates -Cyclone.obj from Cyclone.asm (asmasm.exe Cyclone.asm). Alternatively you can create -Cyclone.obj by using armasm once and then just add it to you project. - -Don't worry if this seem very minimal - its all you need to run as many 68000s as you want. -It works with both C and C++. - - -Byteswapped Memory ------------------- - -If you have used Starscream, A68K or Turbo68K or similar emulators you'll be familiar with this! - -Any memory which the 68000 can access directly must be have every two bytes swapped around. -This is to speed up 16-bit memory accesses, because the 68000 has Big-Endian memory -and ARM has Little-Endian memory (in most cases). - -Now you may think you only technically have to byteswap ROM, not RAM, because -16-bit RAM reads go through a memory handler and you could just return (mem[a]<<8) | mem[a+1]. - -This would work, but remember some systems can execute code from RAM as well as ROM, and -that would fail. -So it's best to use byteswapped ROM and RAM if the 68000 can access it directly. -It's also faster for the memory handlers, because you can do this: - - return *(unsigned short *)(mem+a) - - -Declaring Memory handlers -------------------------- - -Before you can reset or execute 68000 opcodes you must first set up a set of memory handlers. -There are 7 functions you have to set up per CPU, like this: - - static unsigned int MyCheckPc(unsigned int pc) - static unsigned char MyRead8 (unsigned int a) - static unsigned short MyRead16 (unsigned int a) - static unsigned int MyRead32 (unsigned int a) - static void MyWrite8 (unsigned int a,unsigned char d) - static void MyWrite16(unsigned int a,unsigned short d) - static void MyWrite32(unsigned int a,unsigned int d) - -You can think of these functions representing the 68000's memory bus. -The Read and Write functions are called whenever the 68000 reads or writes memory. -For example you might set MyRead8 like this: - - unsigned char MyRead8(unsigned int a) - { - a&=0xffffff; // Clip address to 24-bits - - if (a=0xe00000) return RamData[(a^1)&0xffff]; - return 0xff; // Out of range memory access - } - -The other 5 read/write functions are similar. I'll describe the CheckPc function later on. - - -Declaring a CPU Context ------------------------ - -To declare a CPU simple declare a struct Cyclone in your code (don't forget to include Cyclone.h). -For example to declare two 68000s: - - struct Cyclone MyCpu; - struct Cyclone MyCpu2; - -It's probably a good idea to initialize the memory to zero: - - memset(&MyCpu, 0,sizeof(MyCpu)); - memset(&MyCpu2,0,sizeof(MyCpu2)); - -Next point to your memory handlers: - - MyCpu.checkpc=MyCheckPc; - MyCpu.read8 =MyRead8; - MyCpu.read16 =MyRead16; - MyCpu.read32 =MyRead32; - MyCpu.write8 =MyWrite8; - MyCpu.write16=MyWrite16; - MyCpu.write32=MyWrite32; - -You also need to point the fetch handlers - for most systems out there you can just -point them at the read handlers: - MyCpu.fetch8 =MyRead8; - MyCpu.fetch16 =MyRead16; - MyCpu.fetch32 =MyRead32; - -( Why a different set of function pointers for fetch? - Well there are some systems, the main one being CPS2, which return different data - depending on whether the 'fetch' line on the 68000 bus is high or low. - If this is the case, you can set up different functions for fetch reads. - Generally though you don't need to. ) - -Now you are nearly ready to reset the 68000, except a few more functions, -one of them is: checkpc(). - - -The checkpc() function ----------------------- - -When Cyclone reads opcodes, it doesn't use a memory handler every time, this would be -far too slow, instead it uses a direct pointer to ARM memory. -For example if your Rom image was at 0x3000000 and the program counter was $206, -Cyclone's program counter would be 0x3000206. - -The difference between an ARM address and a 68000 address is also stored in a variable called -'membase'. In the above example it's 0x3000000. To retrieve the real 68k PC, Cyclone just -subtracts 'membase'. - -When a long jump happens, Cyclone calls checkpc(). If the PC is in a different bank, -for example Ram instead of Rom, change 'membase', recalculate the new PC and return it: - -static int MyCheckPc(unsigned int pc) -{ - pc-=MyCpu.membase; // Get the real program counter - - if (pc=0xff0000) MyCpu.membase=(int)RamMem-0xff0000; // Jump to Ram - - return MyCpu.membase+pc; // New program counter -} - -Notice that the membase is always ARM address minus 68000 address. - -The above example doesn't consider mirrored ram, but for an example of what to do see -PicoDrive (in Memory.c). - -The exact cases when checkpc() is called can be configured in config.h. - - -Initialization --------------- - -Add a call to CycloneInit(). This is really only needed to be called once at startup -if you enabled COMPRESS_JUMPTABLE in config.h, but you can add this in any case, -it won't hurt. - - -Almost there - Reset the 68000! -------------------------------- - -Cyclone doesn't provide a reset function, so next we need to Reset the 68000 to get -the initial Program Counter and Stack Pointer. This is obtained from addresses -000000 and 000004. - -Here is code which resets the 68000 (using your memory handlers): - - MyCpu.state_flags=0; // Go to default state (not stopped, halted, etc.) - MyCpu.srh=0x27; // Set supervisor mode - MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer - MyCpu.membase=0; // Will be set by checkpc() - MyCpu.pc=MyCpu.checkpc(MyCpu.read32(4)); // Get Program Counter - -And that's ready to go. - - -Executing the 68000 -------------------- - -To execute the 68000, set the 'cycles' variable to the number of cycles you wish to execute, -and then call CycloneRun with a pointer to the Cyclone structure. - -e.g.: - // Execute 1000 cycles on the 68000: - MyCpu.cycles=1000; CycloneRun(&MyCpu); - -For each opcode, the number of cycles it took is subtracted and the function returns when -it reaches negative number. The result is stored back to MyCpu.cycles. - -e.g. - // Execute one instruction on the 68000: - MyCpu.cycles=0; CycloneRun(&MyCpu); - printf(" The opcode took %d cycles\n", -MyCpu.cycles); - -You should try to execute as many cycles as you can for maximum speed. -The number actually executed may be slightly more than requested, i.e. cycles may come -out with a small negative value: - -e.g. - int todo=12000000/60; // 12Mhz, for one 60hz frame - MyCpu.cycles=todo; CycloneRun(&MyCpu); - printf(" Actually executed %d cycles\n", todo-MyCpu.cycles); - -To calculate the number of cycles executed, use this formula: - Number of cycles requested - Cycle counter at the end - - -Interrupts ----------- - -Causing an interrupt is very simple, simply set the irq variable in the Cyclone structure -to the IRQ number. -To lower the IRQ line, set it to zero. - -e.g: - MyCpu.irq=6; // Interrupt level 6 - MyCpu.cycles=20000; CycloneRun(&MyCpu); - -Note that the interrupt is not actually processed until the next call to CycloneRun, -and the interrupt may not be taken until the 68000 interrupt mask is changed to allow it. - -If you need to force interrupt processing, you can use CycloneFlushIrq() function. -It is the same as doing - -MyCpu.cycles=0; CycloneRun(&MyCpu); - -but is better optimized and doesn't update .cycles (returns them instead). -This function can't be used from memory handlers and has no effect if interrupt is masked. - -The IRQ isn't checked on exiting from a memory handler. If you need to cause interrupt -check immediately, you should change cycle counter to 0 to cause a return from CycloneRun(), -and then call CycloneRun() again or just call CycloneFlushIrq(). Note that you need to -enable MEMHANDLERS_CHANGE_CYCLES in config.h for this to work. - -If you need to do something during the interrupt acknowledge (the moment when interrupt -is taken), you can set USE_INT_ACK_CALLBACK in config.h and specify IrqCallback function. -This function should update the IRQ level (.irq variable in context) and return the -interrupt vector number. But for most cases it should return special constant -CYCLONE_INT_ACK_AUTOVECTOR so that Cyclone uses autovectors, which is what most real -systems were doing. Another less commonly used option is to return CYCLONE_INT_ACK_SPURIOUS -for spurious interrupt. - - -Accessing Program Counter and registers ---------------------------------------- - -You can read most Cyclone's registers directly from the structure at any time. -However, the PC value, CCR and cycle counter are cached in ARM registers and can't -be accessed from memory handlers by default. They are written back and can be -accessed after execution. - -But if you need to access the mentioned registers during execution, you can set -MEMHANDLERS_NEED_* and MEMHANDLERS_CHANGE_* options in config.h - -The Program Counter, should you need to read or write it, is stored with membase -added on. So use this formula to calculate the real 68000 program counter: - - pc = MyCpu.pc - MyCpu.membase; - -For performance reasons Cyclone keeps the status register split into .srh -(status register "high" supervisor byte), .xc for the X flag, and .flags for remaining -CCR flags (in ARM order). To easily read/write the status register as normal 68k -16bit SR register, use CycloneGetSr() and CycloneSetSr() utility functions. - - -Emulating more than one CPU ---------------------------- - -Since everything is based on the structures, emulating more than one cpu at the same time -is just a matter of declaring more than one structures and timeslicing. You can emulate -as many 68000s as you want. -Just set up the memory handlers for each cpu and run each cpu for a certain number of cycles. - -e.g. - // Execute 1000 cycles on 68000 #1: - MyCpu.cycles=1000; CycloneRun(&MyCpu); - - // Execute 1000 cycles on 68000 #2: - MyCpu2.cycles=1000; CycloneRun(&MyCpu2); - - -Quick API reference -------------------- - -void CycloneInit(void); - Initializes Cyclone. Must be called if the jumptable is compressed, - doesn't matter otherwise. - -void CycloneRun(struct Cyclone *pcy); - Runs cyclone for pcy->cycles. Writes amount of cycles left back to - pcy->cycles (always negative). - -unsigned int CycloneGetSr(const struct Cyclone *pcy); - Reads status register in internal form from pcy, converts to standard 68k SR and returns it. - -void CycloneSetSr(struct Cyclone *pcy, unsigned int sr); - Takes standard 68k status register (sr), and updates Cyclone context with it. - -int CycloneFlushIrq(struct Cyclone *pcy); - If .irq is greater than IRQ mask in SR, or it is equal to 7 (NMI), processes interrupt - exception and returns number of cycles used. Otherwise, does nothing and returns 0. - -void CyclonePack(const struct Cyclone *pcy, void *save_buffer); - Writes Cyclone state to save_buffer. This allows to avoid all the trouble figuring what - actually needs to be saved from the Cyclone structure, as saving whole struct Cyclone - to a file will also save various pointers, which may become invalid after your program - is restarted, so simply reloading the structure will cause a crash. save_buffer size - should be 128 bytes (now it is really using less, but this allows future expansion). - -void CycloneUnpack(struct Cyclone *pcy, const void *save_buffer); - Reloads Cyclone state from save_buffer, which was previously saved by CyclonePack(). - This function uses checkpc() callback to rebase the PC, so .checkpc must be initialized - before calling it. - -Callbacks: - -.checkpc -unsigned int (*checkpc)(unsigned int pc); - This function is called when PC changes are performed in 68k code or because of exceptions. - It is passed ARM pointer and should return ARM pointer casted to int. It must also update - .membase if needed. See "The checkpc() function" section above. - -unsigned int (*read8 )(unsigned int a); -unsigned int (*read16 )(unsigned int a); -unsigned int (*read32 )(unsigned int a); - These are the read memory handler callbacks. They are called when 68k code reads from memory. - The parameter is a 68k address in data space, return value is a data value read. Data value - doesn't have to be masked to 8 or 16 bits for read8 or read16, Cyclone will do that itself - if needed. - -unsigned int (*fetch8 )(unsigned int a); -unsigned int (*fetch16)(unsigned int a); -unsigned int (*fetch32)(unsigned int a); - Same as above, but these are reads from program space (PC relative reads mostly). - -void (*write8 )(unsigned int a,unsigned char d); -void (*write16)(unsigned int a,unsigned short d); -void (*write32)(unsigned int a,unsigned int d); - These are called when 68k code writes to data space. d is the data value. - -int (*IrqCallback)(int int_level); - This function is called when Cyclone acknowledges an interrupt. The parameter is the IRQ - level being acknowledged, and return value is exception vector to use, or one of these special - values: CYCLONE_INT_ACK_AUTOVECTOR or CYCLONE_INT_ACK_SPURIOUS. Can be disabled in config.h. - See "Interrupts" section for more information. - -void (*ResetCallback)(void); - Cyclone will call this function if it encounters RESET 68k instruction. - Can be disabled in config.h. - -int (*UnrecognizedCallback)(void); - Cyclone will call this function if it encounters illegal instructions (including A-line and - F-line ones). Can be tuned / disabled in config.h. - - -Function codes --------------- - -Cyclone doesn't pass function codes to it's memory handlers, but they can be calculated: -FC2: just use supervisor state bit from status register (eg. (MyCpu.srh & 0x20) >> 5) -FC1: if we are in fetch* function, then 1, else 0. -FC0: if we are in read* or write*, then 1, else 0. -CPU state (all FC bits set) is active in IrqCallback function. - - -References ----------- - -These documents were used while writing Cyclone and should be useful for those who want to -understand deeper how the 68000 works. - -MOTOROLA M68000 FAMILY Programmer's Reference Manual -common name: 68kPM.pdf - -M68000 8-/16-/32-Bit Microprocessors User's Manual -common name: MC68000UM.pdf - -68000 Undocumented Behavior Notes by Bart Trzynadlowski -http://www.trzy.org/files/68knotes.txt - -Instruction prefetch on the Motorola 68000 processor by Jorge Cwik -http://pasti.fxatari.com/68kdocs/68kPrefetch.html - - -ARM Register Usage ------------------- - -See source code for up to date of register usage, however a summary is here: - - r0-3: Temporary registers - r4 : Current PC + Memory Base (i.e. pointer to next opcode) - r5 : Cycles remaining - r6 : Pointer to Opcode Jump table - r7 : Pointer to Cpu Context - r8 : Current Opcode - r10 : Flags (NZCV) in highest four bits - (r11 : Temporary register) - -Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode. -r9 is not used intentionally, because AAPCS defines it as "platform register", so it's -reserved in some systems. - - -Thanks to... ------------- - -* All the previous code-generating assembler cpu core guys! - Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson - Karl Stenerud and Bart Trzynadlowski - -* Charles Macdonald, for researching just about every console ever -* MameDev+FBA, for keeping on going and going and going - - -What's New ----------- -v0.0099 notaz - * Cyclone no longer uses r9, because AAPCS defines it as "platform register", - so it's reserved in some systems. - * Made SPLIT_MOVEL_PD to affect MOVEM too. - -v0.0088 notaz - - Reduced amount of code in opcode handlers by ~23% by doing the following: - - Removed duplicate opcode handlers - - Optimized code to use less ARM instructions - - Merged some duplicate handler endings - + Cyclone now does better job avoiding pipeline interlocks. - + Replaced incorrect handler of DBT with proper one. - + Changed "MOVEA (An)+ An" behavior. - + Fixed flag behavior of ROXR, ASL, LSR and NBCD in certain situations. - Hopefully got them right now. - + Cyclone no longer sets most significant bits while pushing PC to stack. - Amiga Kickstart depends on this. - + Added optional trace mode emulation. - + Added optional address error emulation. - + Additional functionality added for MAME and other ports (see config.h). - + Added return value for IrqCallback to make it suitable for emulating devices which - pass the vector number during interrupt acknowledge cycle. For usual autovector - processing this function must return CYCLONE_INT_ACK_AUTOVECTOR, so those who are - upgrading must add "return CYCLONE_INT_ACK_AUTOVECTOR;" to their IrqCallback functions. - * Updated documentation. - -v0.0086 notaz - + Cyclone now can be customized to better suit your project, see config.h . - + Added an option to compress the jumptable at compile-time. Must call CycloneInit() - at runtime to decompress it if enabled (see config.h). - + Added missing CHK opcode handler (used by SeaQuest DSV). - + Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis, - memory write-back phase is ignored (but can be enabled in config.h if needed). - + Added missing NBCD and TRAPV opcode handlers. - + Added missing addressing mode for CMP/EOR. - + Added some minor optimizations. - - Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes. - + Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR. - + Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers. - * Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi. - + Added Uninitialized Interrupt emulation. - + Altered timing for about half of opcodes to match Musashi's. - -v0.0082 Reesy - + Change cyclone to clear cycles before returning when halted - + Added Irq call back function. This allows emulators to be notified - when cyclone has taken an interrupt allowing them to set internal flags - which can help fix timing problems. - -v0.0081 notaz - + .asm version was broken and did not compile with armasm. Fixed. - + Finished implementing Stop opcode. Now it really stops the processor. - -v0.0080 notaz - + Added real cmpm opcode, it was using eor handler before this. - Fixes Dune and Sensible Soccer. - -v0.0078 notaz - note: these bugs were actually found Reesy, I reimplemented these by - using his changelog as a guide. - + Fixed a problem with divu which was using long divisor instead of word. - Fixes gear switching in Top Gear 2. - + Fixed btst opcode, The bit to test should shifted a max of 31 or 7 - depending on if a register or memory location is being tested. - + Fixed abcd,sbcd. They did bad decimal correction on invalid BCD numbers - Score counters in Streets of Rage level end work now. - + Changed flag handling of abcd,sbcd,addx,subx,asl,lsl,... - Some ops did not have flag handling at all. - Some ops must not change Z flag when result is zero, but they did. - Shift ops must not change X if shift count is zero, but they did. - There are probably still some flag problems left. - + Patially implemented Stop and Reset opcodes - Fixes Thunderforce IV - -v0.0075 notaz - + Added missing displacement addressing mode for movem (Fantastic Dizzy) - + Added OSP <-> A7 swapping code in opcodes, which change privilege mode - + Implemented privilege violation, line emulator and divide by zero exceptions - + Added negx opcode (Shining Force works!) - + Added overflow detection for divs/divu - -v0.0072 notaz - note: I could only get v0.0069 cyclone, so I had to implement these myself using Dave's - changelog as a guide. - + Fixed a problem with divs - remainder should be negative when divident is negative - + Added movep opcode (Sonic 3 works) - + Fixed a problem with DBcc incorrectly decrementing if the condition is true (Shadow of the Beast) - -v0.0069 - + Added SBCD and the flags for ABCD/SBCD. Score and time now works in games such as - Rolling Thunder 2, Ghouls 'N Ghosts - + Fixed a problem with addx and subx with 8-bit and 16-bit values. - Ghouls 'N' Ghosts now works! - -v0.0068 - + Added ABCD opcode (Streets of Rage works now!) - -v0.0067 - + Added dbCC (After Burner) - + Added asr EA (Sonic 1 Boss/Labyrinth Zone) - + Added andi/ori/eori ccr (Altered Beast) - + Added trap (After Burner) - + Added special case for move.b (a7)+ and -(a7), stepping by 2 - After Burner is playable! Eternal Champions shows more - + Fixed lsr.b/w zero flag (Ghostbusters) - Rolling Thunder 2 now works! - + Fixed N flag for .b and .w arithmetic. Golden Axe works! - -v0.0066 - + Fixed a stupid typo for exg (orr r10,r10, not orr r10,r8), which caused alignment - crashes on Strider - -v0.0065 - + Fixed a problem with immediate values - they weren't being shifted up correctly for some - opcodes. Spiderman works, After Burner shows a bit of graphics. - + Fixed a problem with EA:"110nnn" extension word. 32-bit offsets were being decoded as 8-bit - offsets by mistake. Castlevania Bloodlines seems fine now. - + Added exg opcode - + Fixed asr opcode (Sonic jumping left is fixed) - + Fixed a problem with the carry bit in rol.b (Marble Madness) - -v0.0064 - + Added rtr - + Fixed addq/subq.l (all An opcodes are 32-bit) (Road Rash) - + Fixed various little timings - -v0.0063 - + Added link/unlk opcodes - + Fixed various little timings - + Fixed a problem with dbCC opcode being emitted at set opcodes - + Improved long register access, the EA fetch now does ldr r0,[r7,r0,lsl #2] whenever - possible, saving 1 or 2 cycles on many opcodes, which should give a nice speed up. - + May have fixed N flag on ext opcode? - + Added dasm for link opcode. - -v0.0062 - * I was a bit too keen with the Arithmetic opcodes! Some of them should have been abcd, - exg and addx. Removed the incorrect opcodes, pending re-adding them as abcd, exg and addx. - + Changed unknown opcodes to act as nops. - Not very technical, but fun - a few more games show more graphics ;) - -v0.0060 - + Fixed divu (EA intro) - + Added sf (set false) opcode - SOR2 - * Todo: pea/link/unlk opcodes - -v0.0059: Added remainder to divide opcodes. - - diff --git a/cpu/Cyclone/Disa/Disa.c b/cpu/Cyclone/Disa/Disa.c deleted file mode 100644 index 190e36d..0000000 --- a/cpu/Cyclone/Disa/Disa.c +++ /dev/null @@ -1,886 +0,0 @@ - -// Dave's Disa 68000 Disassembler -#ifndef __GNUC__ -#pragma warning(disable:4115) -#endif -#include -#include -#include "Disa.h" - -unsigned int DisaPc=0; -char *DisaText=NULL; // Text buffer to write in -static char Tasm[]="bwl?"; -static char Comment[64]=""; -unsigned short (*DisaWord)(unsigned int a)=NULL; - -static unsigned int DisaLong(unsigned int a) -{ - unsigned int d=0; - if (DisaWord==NULL) return d; - - d= DisaWord(a)<<16; - d|=DisaWord(a+2)&0xffff; - return d; -} - -// Get text version of the effective address -int DisaGetEa(char *t,int ea,int size) -{ - ea&=0x3f; t[0]=0; - if ((ea&0x38)==0x00) { sprintf(t,"d%d",ea ); return 0; } // 000rrr - if ((ea&0x38)==0x08) { sprintf(t,"a%d",ea&7); return 0; } // 001rrr - if ((ea&0x38)==0x10) { sprintf(t,"(a%d)",ea&7); return 0; } // 010rrr - if ((ea&0x38)==0x18) { sprintf(t,"(a%d)+",ea&7); return 0; } // 011rrr - if ((ea&0x38)==0x20) { sprintf(t,"-(a%d)",ea&7); return 0; } // 100rrr - if ((ea&0x38)==0x28) { sprintf(t,"($%x,a%d)",DisaWord(DisaPc)&0xffff,ea&7); DisaPc+=2; return 0; } // 101rrr - - if ((ea&0x38)==0x30) - { - // 110nnn - An + Disp + D/An - int areg=0,ext=0,off=0,da=0,reg=0,wol=0,scale=0; - ext=DisaWord(DisaPc)&0xffff; - - areg=ea&7; - off=ext&0xff; da =ext&0x8000?'a':'d'; - reg=(ext>>12)&7; wol=ext&0x0800?'l':'w'; - scale=1<<((ext>>9)&3); - - if (scale<2) sprintf(t,"($%x,a%d,%c%d.%c)", off,areg,da,reg,wol); - else sprintf(t,"($%x,a%d,%c%d.%c*%d)",off,areg,da,reg,wol,scale); // 68020 - - DisaPc+=2; - return 0; - } - - if (ea==0x38) { sprintf(t,"$%x.w",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0; } // 111000 - Absolute short - if (ea==0x39) { sprintf(t,"$%x.l",DisaLong(DisaPc)); DisaPc+=4; return 0; } // 111001 - Absolute long - - if (ea==0x3a) - { - // 111010 - PC Relative - int ext=DisaWord(DisaPc)&0xffff; - sprintf(t,"($%x,pc)",ext); - sprintf(Comment,"; =%x",DisaPc+(short)ext); // Comment where pc+ext is - DisaPc+=2; - return 0; - } - - if (ea==0x3b) - { - // 111011 - PC Relative + D/An - int ext=0,off=0,da=0,reg=0,wol=0,scale=0; - ext=DisaWord(DisaPc)&0xffff; - - off=ext&0xff; da =ext&0x8000?'a':'d'; - reg=(ext>>12)&7; wol=ext&0x0800?'l':'w'; - scale=1<<((ext>>9)&3); - - if (scale<2) sprintf(t,"($%x,pc,%c%d.%c)", off,da,reg,wol); - else sprintf(t,"($%x,pc,%c%d.%c*%d)",off,da,reg,wol,scale); // 68020 - - sprintf(Comment,"; =%x",DisaPc+(char)off); // Comment where pc+ext is - DisaPc+=2; - return 0; - } - - if (ea==0x3c) - { - // 111100 - Immediate - switch (size) - { - case 0: sprintf(t,"#$%x",DisaWord(DisaPc)&0x00ff); DisaPc+=2; return 0; - case 1: sprintf(t,"#$%x",DisaWord(DisaPc)&0xffff); DisaPc+=2; return 0; - case 2: sprintf(t,"#$%x",DisaLong(DisaPc) ); DisaPc+=4; return 0; - } - return 1; - } - -// Unknown effective address - sprintf(t,"ea=(%d%d%d %d%d%d)", - (ea>>5)&1,(ea>>4)&1,(ea>>3)&1, - (ea>>2)&1,(ea>>1)&1, ea &1); - return 1; -} - -static void GetOffset(char *text) -{ - int off=(short)DisaWord(DisaPc); DisaPc+=2; - - if (off<0) sprintf(text,"-$%x",-off); - else sprintf(text,"$%x", off); -} - -// ================ Opcodes 0x0000+ ================ -static int DisaArithImm(int op) -{ - // Or/And/Sub/Add/Eor/Cmp Immediate 0000ttt0 xxDDDddd (tt=type, xx=size extension, DDDddd=Dest ea) - int dea=0; - char seat[64]="",deat[64]=""; - int type=0,size=0; - char *arith[8]={"or","and","sub","add","?","eor","cmp","?"}; - - type=(op>>9)&7; if (type==4 || type>=7) return 1; - size=(op>>6)&3; if (size>=3) return 1; - dea=op&0x3f; if (dea==0x3c) return 1; - - DisaGetEa(seat,0x3c,size); - DisaGetEa(deat,dea, size); - - sprintf(DisaText,"%si.%c %s, %s",arith[type],Tasm[size],seat,deat); - return 0; -} - -// ================ Opcodes 0x0108+ ================ -static int DisaMovep(int op) -{ - // movep.x (Aa),Dn - 0000nnn1 dx001aaa nn - int dn=0,dir=0,size=0,an=0; - char offset[32]=""; - - dn =(op>>9)&7; - dir =(op>>7)&1; - size=(op>>6)&1; size++; - an = op &7; - - GetOffset(offset); - if (dir) sprintf(DisaText,"movep.%c d%d, (%s,a%d)",Tasm[size],dn,offset,an); - else sprintf(DisaText,"movep.%c (%s,a%d), d%d",Tasm[size],offset,an,dn); - - return 0; -} - -// ================ Opcodes 0x007c+ ================ -static int DisaArithSr(int op) -{ - // Ori/Andi/Eori $nnnn,sr 0000t0tx 0s111100 - char *opcode[6]={"ori","andi","","","","eori"}; - char seat[64]=""; - int type=0,size=0; - - type=(op>>9)&5; - size=(op>>6)&1; - - DisaGetEa(seat,0x3c,size); - sprintf(DisaText,"%s.%c %s, %s", opcode[type], Tasm[size], seat, size?"sr":"ccr"); - - return 0; -} - -// ================ Opcodes 0x0100+ ================ -static int DisaBtstReg(int op) -{ - // Btst/Bchg/Bclr/Bset 0000nnn1 tteeeeee (nn=reg number, eeeeee=Dest ea) - int type=0; - int sea=0,dea=0; - char seat[64]="",deat[64]=""; - char *opcode[4]={"btst","bchg","bclr","bset"}; - - sea =(op>>9)&7; - type=(op>>6)&3; - dea= op&0x3f; - - if ((dea&0x38)==0x08) return 1; // movep - DisaGetEa(seat,sea,0); - DisaGetEa(deat,dea,0); - - sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat); - return 0; -} - -// ================ Opcodes 0x0800+ ================ -static int DisaBtstImm(int op) -{ - // Btst/Bchg/Bclr/Bset 00001000 tteeeeee 00 nn (eeeeee=ea, nn=bit number) - int type=0; - char seat[64]="",deat[64]=""; - char *opcode[4]={"btst","bchg","bclr","bset"}; - - type=(op>>6)&3; - DisaGetEa(seat, 0x3c,0); - DisaGetEa(deat,op&0x3f,0); - - sprintf(DisaText,"%s %s, %s",opcode[type],seat,deat); - return 0; -} - -// ================ Opcodes 0x1000+ ================ -static int DisaMove(int op) -{ - // Move 00xxdddD DDssssss (xx=size extension, ssssss=Source EA, DDDddd=Dest ea) - int sea=0,dea=0; - char inst[64]="",seat[64]="",deat[64]=""; - char *movea=""; - int size=0; - - if ((op&0x01c0)==0x0040) movea="a"; // See if it's a movea opcode - - // Find size extension - switch (op&0x3000) - { - case 0x1000: size=0; break; - case 0x3000: size=1; break; - case 0x2000: size=2; break; - default: return 1; - } - - sea = op&0x003f; - DisaGetEa(seat,sea,size); - - dea =(op&0x01c0)>>3; - dea|=(op&0x0e00)>>9; - DisaGetEa(deat,dea,size); - - sprintf(inst,"move%s.%c",movea,Tasm[size]); - sprintf(DisaText,"%s %s, %s",inst,seat,deat); - return 0; -} - -// ================ Opcodes 0x4000+ ================ -static int DisaNeg(int op) -{ - // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA) - char eat[64]=""; - int type=0,size=0; - char *opcode[4]={"negx","clr","neg","not"}; - - type=(op>>9)&3; - size=(op>>6)&3; if (size>=3) return 1; - DisaGetEa(eat,op&0x3f,size); - - sprintf(DisaText,"%s.%c %s",opcode[type],Tasm[size],eat); - return 0; -} - -// ================ Opcodes 0x40c0+ ================ -static int DisaMoveSr(int op) -{ - // 01000tt0 11eeeeee (tt=type, xx=size, eeeeee=EA) - int type=0,ea=0; - char eat[64]=""; - - type=(op>>9)&3; - ea=op&0x3f; - DisaGetEa(eat,ea,1); - - switch (type) - { - default: sprintf(DisaText,"move sr, %s", eat); break; - case 1: sprintf(DisaText,"move ccr, %s",eat); break; - case 2: sprintf(DisaText,"move %s, ccr",eat); break; - case 3: sprintf(DisaText,"move %s, sr", eat); break; - } - return 0; -} - -static int OpChk(int op) -{ - int sea=0,dea=0; - char seat[64]="",deat[64]=""; - - sea=op&0x003f; - DisaGetEa(seat,sea,0); - - dea=(op>>9)&7; dea|=8; - DisaGetEa(deat,dea,2); - - sprintf(DisaText,"chk %s, %s",seat,deat); - return 0; -} - -// ================ Opcodes 0x41c0+ ================ -static int DisaLea(int op) -{ - // Lea 0100nnn1 11eeeeee (eeeeee=ea) - int sea=0,dea=0; - char seat[64]="",deat[64]=""; - - sea=op&0x003f; - DisaGetEa(seat,sea,0); - - dea=(op>>9)&7; dea|=8; - DisaGetEa(deat,dea,2); - - sprintf(DisaText,"lea %s, %s",seat,deat); - return 0; -} - -static int MakeRegList(char *list,int mask,int ea) -{ - int reverse=0,i=0,low=0,len=0; - - if ((ea&0x38)==0x20) reverse=1; // -(An), bitfield is reversed - - mask&=0xffff; list[0]=0; - - for (i=0;i<17;i++) - { - int bit=0; - - // Mask off bit i: - if (reverse) bit=0x8000>>i; else bit=1<0) if (list[len-1]=='/') list[len-1]=0; - return 0; -} - -// ================ Opcodes 0x4800+ ================ -static int DisaNbcd(int op) -{ - // Nbcd 01001000 00eeeeee (eeeeee=ea) - int ea=0; - char eat[64]=""; - - ea=op&0x003f; - DisaGetEa(eat,ea,0); - - sprintf(DisaText,"nbcd %s",eat); - return 0; -} - -// ================ Opcodes 0x4840+ ================ -static int DisaSwap(int op) -{ - // Swap, 01001000 01000nnn swap Dn - sprintf(DisaText,"swap d%d",op&7); - return 0; -} - -// ================ Opcodes 0x4850+ ================ -static int DisaPea(int op) -{ - // Pea 01001000 01eeeeee (eeeeee=ea) pea - int ea=0; - char eat[64]=""; - - ea=op&0x003f; if (ea<0x10) return 1; // swap opcode - DisaGetEa(eat,ea,2); - - sprintf(DisaText,"pea %s",eat); - return 0; -} - -// ================ Opcodes 0x4880+ ================ -static int DisaExt(int op) -{ - // Ext 01001000 1x000nnn (x=size, eeeeee=EA) - char eat[64]=""; - int size=0; - - size=(op>>6)&1; size++; - DisaGetEa(eat,op&0x3f,size); - - sprintf(DisaText,"ext.%c %s",Tasm[size],eat); - return 0; -} - -// ================ Opcodes 0x4890+ ================ -static int DisaMovem(int op) -{ - // Movem 01001d00 1xeeeeee regmask d=direction, x=size, eeeeee=EA - int dir=0,size=0; - int ea=0,mask=0; - char list[64]="",eat[64]=""; - - dir=(op>>10)&1; - size=((op>>6)&1)+1; - ea=op&0x3f; if (ea<0x10) return 1; // ext opcode - - mask=DisaWord(DisaPc)&0xffff; DisaPc+=2; - - MakeRegList(list,mask,ea); // Turn register mask into text - DisaGetEa(eat,ea,size); - - if (dir) sprintf(DisaText,"movem.%c %s, %s",Tasm[size],eat,list); - else sprintf(DisaText,"movem.%c %s, %s",Tasm[size],list,eat); - return 0; -} - -// ================ Opcodes 0x4e40+ ================ -static int DisaTrap(int op) -{ - sprintf(DisaText,"trap #%d",op&0xf); - return 0; -} - -// ================ Opcodes 0x4e50+ ================ -static int DisaLink(int op) -{ - // Link opcode, 01001110 01010nnn dd link An,#offset - char eat[64]=""; - char offset[32]=""; - - DisaGetEa(eat,(op&7)|8,0); - GetOffset(offset); - - sprintf(DisaText,"link %s,#%s",eat,offset); - - return 0; -} - -// ================ Opcodes 0x4e58+ ================ -static int DisaUnlk(int op) -{ - // Link opcode, 01001110 01011nnn dd unlk An - char eat[64]=""; - - DisaGetEa(eat,(op&7)|8,0); - sprintf(DisaText,"unlk %s",eat); - - return 0; -} - -// ================ Opcodes 0x4e60+ ================ -static int DisaMoveUsp(int op) -{ - // Move USP opcode, 01001110 0110dnnn move An to/from USP (d=direction) - int ea=0,dir=0; - char eat[64]=""; - - dir=(op>>3)&1; - ea=(op&7)|8; - DisaGetEa(eat,ea,0); - - if (dir) sprintf(DisaText,"move usp, %s",eat); - else sprintf(DisaText,"move %s, usp",eat); - return 0; -} - -// ================ Opcodes 0x4e70+ ================ -static int Disa4E70(int op) -{ - char *inst[8]={"reset","nop","stop","rte","rtd","rts","trapv","rtr"}; - int n=0; - - n=op&7; - - sprintf(DisaText,"%s",inst[n]); - - //todo - 'stop' with 16 bit data - - return 0; -} - -// ================ Opcodes 0x4a00+ ================ -static int DisaTst(int op) -{ - // Tst 01001010 xxeeeeee (eeeeee=ea) - int ea=0; - char eat[64]=""; - int size=0; - - ea=op&0x003f; - DisaGetEa(eat,ea,0); - size=(op>>6)&3; if (size>=3) return 1; - - sprintf(DisaText,"tst.%c %s",Tasm[size],eat); - return 0; -} - -static int DisaTas(int op) -{ - // Tas 01001010 11eeeeee (eeeeee=ea) - int ea=0; - char eat[64]=""; - - ea=op&0x003f; - DisaGetEa(eat,ea,0); - - sprintf(DisaText,"tas %s",eat); - return 0; -} - -// ================ Opcodes 0x4e80+ ================ -static int DisaJsr(int op) -{ - // Jsr/Jmp 0100 1110 1mEE Eeee (eeeeee=ea m=1=jmp) - int sea=0; - char seat[64]=""; - - sea=op&0x003f; - DisaGetEa(seat,sea,0); - - sprintf(DisaText,"j%s %s", op&0x40?"mp":"sr", seat); - return 0; -} - -// ================ Opcodes 0x5000+ ================ -static int DisaAddq(int op) -{ - // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA) - int num=0,type=0,size=0,ea=0; - char eat[64]=""; - - num =(op>>9)&7; if (num==0) num=8; - type=(op>>8)&1; - size=(op>>6)&3; if (size>=3) return 1; - ea = op&0x3f; - - DisaGetEa(eat,ea,size); - - sprintf(DisaText,"%s.%c #%d, %s",type?"subq":"addq",Tasm[size],num,eat); - return 0; -} - -// ================ Opcodes 0x50c0+ ================ -static int DisaSet(int op) -{ - // 0101cccc 11eeeeee (sxx ea) - static char *cond[16]= - {"t" ,"f", "hi","ls","cc","cs","ne","eq", - "vc","vs","pl","mi","ge","lt","gt","le"}; - char *cc=""; - int ea=0; - char eat[64]=""; - - cc=cond[(op>>8)&0xf]; // Get condition code - ea=op&0x3f; - if ((ea&0x38)==0x08) return 1; // dbra, not scc - - DisaGetEa(eat,ea,0); - sprintf(DisaText,"s%s %s",cc,eat); - return 0; -} - -// ================ Opcodes 0x50c8+ ================ -static int DisaDbra(int op) -{ - // 0101cccc 11001nnn offset (dbra/dbxx Rn,offset) - int dea=0; char deat[64]=""; - int pc=0,Offset=0; - - static char *BraCode[16]= - {"bt" ,"bra","bhi","bls","bcc","bcs","bne","beq", - "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"}; - char *Bra=""; - - dea=op&7; - DisaGetEa(deat,dea,2); - - // Get condition code - Bra=BraCode[(op>>8)&0xf]; - - // Get offset - pc=DisaPc; - Offset=(short)DisaWord(DisaPc); DisaPc+=2; - - sprintf(DisaText,"d%s %s, %x",Bra,deat,pc+Offset); - return 0; -} - -// ================ Opcodes 0x6000+ ================ -static int DisaBranch(int op) -{ - // Branch 0110cccc nn (cccc=condition) - int pc=0,Offset=0; - - static char *BraCode[16]= - {"bra","bsr","bhi","bls","bcc","bcs","bne","beq", - "bvc","bvs","bpl","bmi","bge","blt","bgt","ble"}; - char *Bra=""; - - // Get condition code - Bra=BraCode[(op>>8)&0x0f]; - - // Get offset - pc=DisaPc; - Offset=(char)(op&0xff); - if (Offset== 0) { Offset=(short)DisaWord(DisaPc); DisaPc+=2; } - else if (Offset==-1) { Offset= DisaLong(DisaPc); DisaPc+=4; } - - sprintf(DisaText,"%s %x",Bra,pc+Offset); - return 0; -} - -// ================ Opcodes 0x7000+ ================ -static int DisaMoveq(int op) -{ - // Moveq 0111rrr0 nn (rrr=Dest register, nn=data) - - int dea=0; char deat[64]=""; - char *inst="moveq"; - int val=0; - - dea=(op>>9)&7; - DisaGetEa(deat,dea,2); - - val=(char)(op&0xff); - sprintf(DisaText,"%s #$%x, %s",inst,val,deat); - return 0; -} - -// ================ Opcodes 0x8000+ ================ -static int DisaArithReg(int op) -{ - // 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA) - int type=0,size=0,dir=0,rea=0,ea=0; - char reat[64]="",eat[64]=""; - char *opcode[]={"or","sub","","","and","add"}; - - type=(op>>12)&5; - rea =(op>> 9)&7; - dir =(op>> 8)&1; - size=(op>> 6)&3; if (size>=3) return 1; - ea = op&0x3f; - - if (dir && ea<0x10) return 1; // addx opcode - - DisaGetEa(reat,rea,size); - DisaGetEa( eat, ea,size); - - if (dir) sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],reat,eat); - else sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],eat,reat); - return 0; -} - -// ================ Opcodes 0x8100+ ================ -static int DisaAbcd(int op) -{ - // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad) - int type=0; - int dn=0,addr=0,sn=0; - char *opcode[]={"sbcd","abcd"}; - - type=(op>>14)&1; - dn =(op>> 9)&7; - addr=(op>> 3)&1; - sn = op &7; - - if (addr) sprintf(DisaText,"%s -(a%d), -(a%d)",opcode[type],sn,dn); - else sprintf(DisaText,"%s d%d, d%d", opcode[type],sn,dn); - - return 0; -} - -// ================ Opcodes 0x80c0+ ================ -static int DisaMul(int op) -{ - // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA) - int type=0,rea=0,sign=0,ea=0,size=1; - char reat[64]="",eat[64]=""; - char *opcode[2]={"div","mul"}; - - type=(op>>14)&1; // div/mul - rea =(op>> 9)&7; - sign=(op>> 8)&1; - ea = op&0x3f; - - DisaGetEa(reat,rea,size); - DisaGetEa( eat, ea,size); - - sprintf(DisaText,"%s%c.%c %s, %s",opcode[type],sign?'s':'u',Tasm[size],eat,reat); - return 0; -} - -// ================ Opcodes 0x90c0+ ================ -static int DisaAritha(int op) -{ - // Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA) - int type=0,size=0,sea=0,dea=0; - char seat[64]="",deat[64]=""; - char *aritha[4]={"suba","cmpa","adda",""}; - - type=(op>>13)&3; if (type>=3) return 1; - size=(op>>8)&1; size++; - dea =(op>>9)&7; dea|=8; // Dest=An - sea = op&0x003f; // Source - - DisaGetEa(seat,sea,size); - DisaGetEa(deat,dea,size); - - sprintf(DisaText,"%s.%c %s, %s",aritha[type],Tasm[size],seat,deat); - return 0; -} - -// ================ Opcodes 0xb000+ ================ -static int DisaCmpEor(int op) -{ - // Cmp/Eor 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea) - char reat[64]="",eat[64]=""; - int type=0,size=0; - - type=(op>>8)&1; - size=(op>>6)&3; if (size>=3) return 1; - DisaGetEa(reat,(op>>9)&7,size); - DisaGetEa(eat, op&0x3f, size); - - if (type) sprintf(DisaText,"eor.%c %s, %s",Tasm[size],reat,eat); - else sprintf(DisaText,"cmp.%c %s, %s",Tasm[size],eat,reat); - return 0; -} - -static int DisaCmpm(int op) -{ - char seat[64]="",deat[64]=""; - int type=0,size=0,sea,dea; - - type=(op>>8)&1; - size=(op>>6)&3; if (size>=3) return 1; - sea=(op&7)|0x18; - dea=(op>>9)&0x3f; - DisaGetEa(seat,sea,size); - DisaGetEa(deat,dea,size); - - sprintf(DisaText,"cmpm.%c %s, %s",Tasm[size],seat,deat); - return 0; -} - - -// ================ Opcodes 0xc140+ ================ -// 1100ttt1 01000sss exg ds,dt -// 1100ttt1 01001sss exg as,at -// 1100ttt1 10001sss exg as,dt -static int DisaExg(int op) -{ - int tr=0,type=0,sr=0; - - tr =(op>>9)&7; - type= op&0xf8; - sr = op&7; - - if (type==0x40) sprintf(DisaText,"exg d%d, d%d",sr,tr); - else if (type==0x48) sprintf(DisaText,"exg a%d, a%d",sr,tr); - else if (type==0x88) sprintf(DisaText,"exg a%d, d%d",sr,tr); - else return 1; - - return 0; -} - -// ================ Opcodes 0xd100+ ================ -static int DisaAddx(int op) -{ - // 1t01ddd1 xx000sss addx - int type=0,size=0,dea=0,sea=0,mem; - char deat[64]="",seat[64]=""; - char *opcode[6]={"","subx","","","","addx"}; - - type=(op>>12)&5; - dea =(op>> 9)&7; - size=(op>> 6)&3; if (size>=3) return 1; - sea = op&7; - mem = op&8; - if(mem) { sea+=0x20; dea+=0x20; } - - DisaGetEa(deat,dea,size); - DisaGetEa(seat,sea,size); - - sprintf(DisaText,"%s.%c %s, %s",opcode[type],Tasm[size],seat,deat); - return 0; -} - -// ================ Opcodes 0xe000+ ================ -static char *AsrName[4]={"as","ls","rox","ro"}; -static int DisaAsr(int op) -{ - // Asr/l/Ror/l etc - 1110cccd xxuttnnn - // (ccc=count, d=direction xx=size extension, u=use reg for count, tt=type, nnn=register Dn) - int count=0,dir=0,size=0,usereg=0,type=0,num=0; - - count =(op>>9)&7; - dir =(op>>8)&1; - size =(op>>6)&3; if (size>=3) return 1; // todo Asr EA - usereg=(op>>5)&1; - type =(op>>3)&3; - num = op &7; // Register number - - if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8 - - sprintf(DisaText,"%s%c.%c %c%d, d%d", - AsrName[type], dir?'l':'r', Tasm[size], - usereg?'d':'#', count, num); - return 0; -} - -static int DisaAsrEa(int op) -{ - // Asr/l/Ror/l etc EA - 11100ttd 11eeeeee - int type=0,dir=0,size=1; - char eat[64]=""; - - type=(op>>9)&3; - dir =(op>>8)&1; - DisaGetEa(eat,op&0x3f,size); - - sprintf(DisaText,"%s%c.w %s", AsrName[type], dir?'l':'r', eat); - return 0; -} - -// ================================================================= - -static int TryOp(int op) -{ - if ((op&0xf100)==0x0000) DisaArithImm(op); // Ori/And/Sub/Add/Eor/Cmp Immediate - if ((op&0xf5bf)==0x003c) DisaArithSr(op); // Ori/Andi/Eori $nnnn,sr - if ((op&0xf100)==0x0100) DisaBtstReg(op); - if ((op&0xf138)==0x0108) DisaMovep(op); - if ((op&0xff00)==0x0800) DisaBtstImm(op); // Btst/Bchg/Bclr/Bset - if ((op&0xc000)==0x0000) DisaMove(op); - if ((op&0xf900)==0x4000) DisaNeg(op); // Negx/Clr/Neg/Not - if ((op&0xf140)==0x4100) OpChk(op); - if ((op&0xf1c0)==0x41c0) DisaLea(op); - if ((op&0xf9c0)==0x40c0) DisaMoveSr(op); - if ((op&0xffc0)==0x4800) DisaNbcd(op); - if ((op&0xfff8)==0x4840) DisaSwap(op); - if ((op&0xffc0)==0x4840) DisaPea(op); - if ((op&0xffb8)==0x4880) DisaExt(op); - if ((op&0xfb80)==0x4880) DisaMovem(op); - if ((op&0xff00)==0x4a00) DisaTst(op); - if ((op&0xffc0)==0x4ac0) DisaTas(op); - if ((op&0xfff0)==0x4e40) DisaTrap(op); - if ((op&0xfff8)==0x4e50) DisaLink(op); - if ((op&0xfff8)==0x4e58) DisaUnlk(op); - if ((op&0xfff0)==0x4e60) DisaMoveUsp(op); - if ((op&0xfff8)==0x4e70) Disa4E70(op); - if ((op&0xff80)==0x4e80) DisaJsr(op); - if ((op&0xf000)==0x5000) DisaAddq(op); - if ((op&0xf0c0)==0x50c0) DisaSet(op); - if ((op&0xf0f8)==0x50c8) DisaDbra(op); - if ((op&0xf000)==0x6000) DisaBranch(op); - if ((op&0xa000)==0x8000) DisaArithReg(op); // Or/Sub/And/Add - if ((op&0xb1f0)==0x8100) DisaAbcd(op); - if ((op&0xb130)==0x9100) DisaAddx(op); - if ((op&0xb0c0)==0x80c0) DisaMul(op); - if ((op&0xf100)==0x7000) DisaMoveq(op); - if ((op&0x90c0)==0x90c0) DisaAritha(op); - if ((op&0xf000)==0xb000) DisaCmpEor(op); - if ((op&0xf138)==0xb108) DisaCmpm(op); - if ((op&0xf130)==0xc100) DisaExg(op); - if ((op&0xf000)==0xe000) DisaAsr(op); - if ((op&0xf8c0)==0xe0c0) DisaAsrEa(op); - - // Unknown opcoode - return 0; -} - -int DisaGet() -{ - int op=0; - if (DisaWord==NULL) return 1; - - Comment[0]=0; - DisaText[0]=0; // Assume opcode unknown - - op=DisaWord(DisaPc)&0xffff; DisaPc+=2; - TryOp(op); - strcat(DisaText,Comment); - - // Unknown opcoode - return 0; -} diff --git a/cpu/Cyclone/Disa/Disa.h b/cpu/Cyclone/Disa/Disa.h deleted file mode 100644 index 1ef18fc..0000000 --- a/cpu/Cyclone/Disa/Disa.h +++ /dev/null @@ -1,18 +0,0 @@ - -// Dave's Disa 68000 Disassembler - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned int DisaPc; -extern char *DisaText; // Text buffer to write in - -extern unsigned short (*DisaWord)(unsigned int a); -int DisaGetEa(char *t,int ea,int size); - -int DisaGet(); - -#ifdef __cplusplus -} // End of extern "C" -#endif diff --git a/cpu/Cyclone/Ea.cpp b/cpu/Cyclone/Ea.cpp deleted file mode 100644 index 4be33e1..0000000 --- a/cpu/Cyclone/Ea.cpp +++ /dev/null @@ -1,493 +0,0 @@ - -#include "app.h" - -int earead_check_addrerr = 1, eawrite_check_addrerr = 0; - -// some ops use non-standard cycle counts for EAs, so are listed here. -// all constants borrowed from the MUSASHI core by Karl Stenerud. - -/* Extra cycles for JMP instruction (000, 010) */ -int g_jmp_cycle_table[8] = -{ - 4, /* EA_MODE_AI */ - 6, /* EA_MODE_DI */ - 10, /* EA_MODE_IX */ - 6, /* EA_MODE_AW */ - 8, /* EA_MODE_AL */ - 6, /* EA_MODE_PCDI */ - 10, /* EA_MODE_PCIX */ - 0, /* EA_MODE_I */ -}; - -/* Extra cycles for JSR instruction (000, 010) */ -int g_jsr_cycle_table[8] = -{ - 4, /* EA_MODE_AI */ - 6, /* EA_MODE_DI */ - 10, /* EA_MODE_IX */ - 6, /* EA_MODE_AW */ - 8, /* EA_MODE_AL */ - 6, /* EA_MODE_PCDI */ - 10, /* EA_MODE_PCIX */ - 0, /* EA_MODE_I */ -}; - -/* Extra cycles for LEA instruction (000, 010) */ -int g_lea_cycle_table[8] = -{ - 4, /* EA_MODE_AI */ - 8, /* EA_MODE_DI */ - 12, /* EA_MODE_IX */ - 8, /* EA_MODE_AW */ - 12, /* EA_MODE_AL */ - 8, /* EA_MODE_PCDI */ - 12, /* EA_MODE_PCIX */ - 0, /* EA_MODE_I */ -}; - -/* Extra cycles for PEA instruction (000, 010) */ -int g_pea_cycle_table[8] = -{ - 6, /* EA_MODE_AI */ - 10, /* EA_MODE_DI */ - 14, /* EA_MODE_IX */ - 10, /* EA_MODE_AW */ - 14, /* EA_MODE_AL */ - 10, /* EA_MODE_PCDI */ - 14, /* EA_MODE_PCIX */ - 0, /* EA_MODE_I */ -}; - -/* Extra cycles for MOVEM instruction (000, 010) */ -int g_movem_cycle_table[8] = -{ - 0, /* EA_MODE_AI */ - 4, /* EA_MODE_DI */ - 6, /* EA_MODE_IX */ - 4, /* EA_MODE_AW */ - 8, /* EA_MODE_AL */ - 0, /* EA_MODE_PCDI */ - 0, /* EA_MODE_PCIX */ - 0, /* EA_MODE_I */ -}; - -// add nonstandard EA -int Ea_add_ns(int *tab, int ea) -{ - if(ea<0x10) return 0; - if((ea&0x38)==0x10) return tab[0]; // (An) (ai) - if(ea<0x28) return 0; - if(ea<0x30) return tab[1]; // ($nn,An) (di) - if(ea<0x38) return tab[2]; // ($nn,An,Rn) (ix) - if(ea==0x38) return tab[3]; // (aw) - if(ea==0x39) return tab[4]; // (al) - if(ea==0x3a) return tab[5]; // ($nn,PC) (pcdi) - if(ea==0x3b) return tab[6]; // ($nn,pc,Rn) (pcix) - if(ea==0x3c) return tab[7]; // #$nnnn (i) - return 0; -} - - -// --------------------------------------------------------------------------- -// Gets the offset of a register for an ea, and puts it in 'r' -// Shifted left by 'shift' -// Doesn't trash anything -static int EaCalcReg(int r,int ea,int mask,int forceor,int shift,int noshift=0) -{ - int i=0,low=0,needor=0; - int lsl=0; - - for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is - mask&=0xf<=8) - { - needor=1; // Need to OR to access A0-7 - if ((g_op>>low)&8) { needor=0; mask|=8<0) ot("lsl #%d\n", lsl); - else ot("lsr #%d\n",-lsl); - } - - return 0; -} - -// EaCalc - ARM Register 'a' = Effective Address -// If ea>=0x10, trashes r0,r2 and r3, else nothing -// size values 0, 1, 2 ~ byte, word, long -// mask shows usable bits in r8 -int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend) -{ - char text[32]=""; - int func=0; - - DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address - func=0x68+(size<<2); // Get correct read handler - - if (ea<0x10) - { - int noshift=0; - if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode - - ot(";@ EaCalc : Get register index into r%d:\n",a); - - EaCalcReg(a,ea,mask,0,2,noshift); - return 0; - } - - ot(";@ EaCalc : Get '%s' into r%d:\n",text,a); - // (An), (An)+, -(An) - if (ea<0x28) - { - int step=1<>=1) low++; // Find out how high up the EA mask is - lsl=2-low; // Having a lsl #x here saves one opcode - if (lsl>=0) ot(" ldr r%d,[r7,r2,lsl #%i]\n",a,lsl); - else if (lsl<0) ot(" ldr r%d,[r7,r2,lsr #%i]\n",a,-lsl); - } - - if ((ea&0x38)==0x18) // (An)+ - { - ot(" add r3,r%d,#%d ;@ Post-increment An\n",a,step); - strr=3; - } - - if ((ea&0x38)==0x20) // -(An) - ot(" sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step); - - if ((ea&0x38)==0x18||(ea&0x38)==0x20) - { - if (ea==0x1f||ea==0x27) - { - ot(" str r%d,[r7,#0x3c] ;@ A7\n",strr); - } - else - { - if (lsl>=0) ot(" str r%d,[r7,r2,lsl #%i]\n",strr,lsl); - else if (lsl<0) ot(" str r%d,[r7,r2,lsr #%i]\n",strr,-lsl); - } - } - - if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles - else Cycles+=size<2 ? 4:8; // (An),(An)+ Extra cycles - return 0; - } - - if (ea<0x30) // ($nn,An) (di) - { - ot(" ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1; - EaCalcReg(2,8,mask,0,0); - ot(" ldr r2,[r7,r2,lsl #2]\n"); - ot(" add r%d,r0,r2 ;@ Add on offset\n",a); - Cycles+=size<2 ? 8:12; // Extra cycles - return 0; - } - - if (ea<0x38) // ($nn,An,Rn) (ix) - { - ot(";@ Get extension word into r3:\n"); - ot(" ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1; - ot(" mov r2,r3,lsr #10\n"); - ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n"); - ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n"); - ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n"); - ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n"); - ot(" mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n"); - ot(" add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n"); - - EaCalcReg(2,8,mask,1,0); - ot(" ldr r2,[r7,r2,lsl #2]\n"); - ot(" add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a); - Cycles+=size<2 ? 10:14; // Extra cycles - return 0; - } - - if (ea==0x38) // (aw) - { - ot(" ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1; - Cycles+=size<2 ? 8:12; // Extra cycles - return 0; - } - - if (ea==0x39) // (al) - { - ot(" ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n"); - ot(" ldrh r0,[r4],#2\n"); pc_dirty=1; - ot(" orr r%d,r0,r2,lsl #16\n",a); - Cycles+=size<2 ? 12:16; // Extra cycles - return 0; - } - - if (ea==0x3a) // ($nn,PC) (pcdi) - { - ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n"); - ot(" sub r0,r4,r0 ;@ Real PC\n"); - ot(" ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1; - ot(" mov r0,r0,lsl #8\n"); - ot(" add r%d,r2,r0,asr #8 ;@ ($nn,PC)\n",a); - Cycles+=size<2 ? 8:12; // Extra cycles - return 0; - } - - if (ea==0x3b) // ($nn,pc,Rn) (pcix) - { - ot(" ldr r0,[r7,#0x60] ;@ Get Memory base\n"); - ot(" ldrh r3,[r4] ;@ Get extension word\n"); - ot(" sub r0,r4,r0 ;@ r0=PC\n"); - ot(" add r4,r4,#2\n"); pc_dirty=1; - ot(" mov r0,r0,asl #8 ;@ use only 24bits of PC\n"); - ot(" mov r2,r3,lsr #10\n"); - ot(" tst r3,#0x0800 ;@ Is Rn Word or Long\n"); - ot(" and r2,r2,#0x3c ;@ r2=Index of Rn\n"); - ot(" ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n"); - ot(" ldrne r2,[r7,r2] ;@ r2=Rn.l\n"); - ot(" mov r3,r3,asl #24 ;@ r3=Get 8-bit signed Disp\n"); - ot(" add r2,r2,r3,asr #24 ;@ r2=Disp+Rn\n"); - ot(" add r%d,r2,r0,asr #8 ;@ r%d=Disp+PC+Rn\n",a,a); - Cycles+=size<2 ? 10:14; // Extra cycles - return 0; - } - - if (ea==0x3c) // #$nnnn (i) - { - if (size<2) - { - ot(" ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1; - Cycles+=4; // Extra cycles - return 0; - } - - ot(" ldrh r2,[r4],#2 ;@ Fetch immediate value\n"); - ot(" ldrh r3,[r4],#2\n"); pc_dirty=1; - ot(" orr r%d,r3,r2,lsl #16\n",a); - Cycles+=8; // Extra cycles - return 0; - } - - return 1; -} - -// --------------------------------------------------------------------------- -// Read effective address in (ARM Register 'a') to ARM register 'v' -// 'a' and 'v' can be anything but 0 is generally best (for both) -// If (ea<0x10) nothing is trashed, else r0-r3 is trashed -// If 'top' is given, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000 -// If top is 0 and sign_extend is not, then ARM register v is sign extended, -// e.g. 0xc000 -> 0xffffc000 (else it may or may not be sign extended) - -int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend) -{ - char text[32]=""; - int shift=0; - - shift=32-(8<=2||(size==0&&(top||!sign_extend))) { - if(mask) - for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is - lsl=2-low; // Having a lsl #2 here saves one opcode - } - - if (top||!sign_extend) nsarm=3; - - ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v); - - if (lsl>0) ot(" ldr%s r%d,[r7,r%d,lsl #%i]\n",Narm[nsarm],v,a,lsl); - else if (lsl<0) ot(" ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[nsarm],v,a,-lsl); - else ot(" ldr%s r%d,[r7,r%d]\n",Sarm[nsarm],v,a); - - if (top&&shift) ot(" mov r%d,r%d,asl #%d\n",v,v,shift); - - ot("\n"); return 0; - } - - ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v); - - if (ea==0x3c) - { - int asl=0; - - if (top) asl=shift; - - if (asl) ot(" mov r%d,r%d,asl #%d\n",v,a,asl); - else if (v!=a) ot(" mov r%d,r%d\n",v,a); - ot("\n"); return 0; - } - - if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a,earead_check_addrerr); // Fetch - else MemHandler(0,size,a,earead_check_addrerr); // Read - - // defaults to 1, as most things begins with a read - earead_check_addrerr=1; - - if (sign_extend) - { - int d_reg=0; - if (shift) { - ot(" mov r%d,r%d,asl #%d\n",v,d_reg,shift); - d_reg=v; - } - if (!top && shift) { - ot(" mov r%d,r%d,asr #%d\n",v,d_reg,shift); - d_reg=v; - } - if (d_reg != v) - ot(" mov r%d,r%d\n",v,d_reg); - } - else - { - if (top && shift) - ot(" mov r%d,r0,asl #%d\n",v,shift); - else if (v!=0) - ot(" mov r%d,r0\n",v); - } - - ot("\n"); return 0; -} - -// calculate EA and read -// if (ea < 0x10) nothing is trashed -// if (ea == 0x3c) r2 and r3 are trashed -// else r0-r3 are trashed -// size values 0, 1, 2 ~ byte, word, long -// r_ea is reg to store ea in (-1 means ea is not needed), r is dst reg -// if sign_extend is 0, non-32bit values will have MS bits undefined -int EaCalcRead(int r_ea,int r,int ea,int size,int mask,int sign_extend) -{ - if (ea<0x10) - { - if (r_ea==-1) - { - r_ea=r; - if (!sign_extend) size=2; - } - } - else if (ea==0x3c) // #imm - { - r_ea=r; - } - else - { - if (r_ea==-1) r_ea=0; - } - - EaCalc (r_ea,mask,ea,size,0,sign_extend); - EaRead (r_ea, r,ea,size,mask,0,sign_extend); - - return 0; -} - -int EaCalcReadNoSE(int r_ea,int r,int ea,int size,int mask) -{ - return EaCalcRead(r_ea,r,ea,size,mask,0); -} - -// Return 1 if we can read this ea -int EaCanRead(int ea,int size) -{ - if (size<0) - { - // LEA: - // These don't make sense?: - if (ea< 0x10) return 0; // Register - if (ea==0x3c) return 0; // Immediate - if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An - } - - if (ea<=0x3c) return 1; - return 0; -} - -// --------------------------------------------------------------------------- -// Write effective address (ARM Register 'a') with ARM register 'v' -// Trashes r0-r3,r12,lr; 'a' can be 0 or 2+, 'v' can be 1 or higher -// If a==0 and v==1 it's faster though. -int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea) -{ - char text[32]=""; - int shift=0; - - if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; } - - if (top) shift=32-(8<=2||(size==0&&(top||!sign_extend_ea))) { - if(mask) - for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is - lsl=2-low; // Having a lsl #x here saves one opcode - } - - ot(";@ EaWrite: r%d into register[r%d]:\n",v,a); - if (shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift); - - if (lsl>0) ot(" str%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl); - else if (lsl<0) ot(" str%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl); - else ot(" str%s r%d,[r7,r%d]\n",Narm[size&3],v,a); - - ot("\n"); return 0; - } - - ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a); - - if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; } - - if (shift) ot(" mov r1,r%d,asr #%d\n",v,shift); - else if (v!=1) ot(" mov r1,r%d\n",v); - - MemHandler(1,size,a,eawrite_check_addrerr); // Call write handler - - // not check by default, because most cases are rmw and - // address was already checked before reading - eawrite_check_addrerr = 0; - - ot("\n"); return 0; -} - -// Return 1 if we can write this ea -int EaCanWrite(int ea) -{ - if (ea<=0x39) return 1; // 3b? - return 0; -} -// --------------------------------------------------------------------------- - -// Return 1 if EA is An reg -int EaAn(int ea) -{ - if((ea&0x38)==8) return 1; - return 0; -} - diff --git a/cpu/Cyclone/Main.cpp b/cpu/Cyclone/Main.cpp deleted file mode 100644 index 8f00bb1..0000000 --- a/cpu/Cyclone/Main.cpp +++ /dev/null @@ -1,1298 +0,0 @@ - -#include "app.h" - -static FILE *AsmFile=NULL; - -static int CycloneVer=0x0099; // Version number of library -int *CyJump=NULL; // Jump table -int ms=USE_MS_SYNTAX; // If non-zero, output in Microsoft ARMASM format -const char * const Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1,2 -const char * const Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2 -int Cycles; // Current cycles for opcode -int pc_dirty; // something changed PC during processing -int arm_op_count; - -// opcodes often used by games -static const unsigned short hot_opcodes[] = { - 0x6701, // beq $3 - 0x6601, // bne $3 - 0x51c8, // dbra Dn, $2 - 0x4a38, // tst.b $0.w - 0xd040, // add.w Dn, Dn - 0x4a79, // tst.w $0.l - 0x0240, // andi.w #$0, D0 - 0x2038, // move.l $0.w, D0 - 0xb0b8, // cmp.l $0.w, D0 - 0x6001, // bra $3 - 0x30c0, // move.w D0, (A0)+ - 0x3028, // move.w ($0,A0), D0 - 0x0c40, // cmpi.w #$0, D0 - 0x0c79, // cmpi.w #$0, $0.l - 0x4e75, // rts - 0x4e71, // nop - 0x3000, // move.w D0, D0 - 0x0839, // btst #$0, $0.l - 0x7000, // moveq #$0, D0 - 0x3040, // movea.w D0, A0 - 0x0838, // btst #$0, $0.w - 0x4a39, // tst.b $0.l - 0x33d8, // move.w (A0)+, $0.l - 0x6700, // beq $2 - 0xb038, // cmp.b $0.w, D0 - 0x3039, // move.w $0.l, D0 - 0x4840, // swap D0 - 0x6101, // bsr $3 - 0x6100, // bsr $2 - 0x5e40, // addq.w #7, D0 - 0x1039, // move.b $0.l, D0 - 0x20c0, // move.l D0, (A0)+ - 0x1018, // move.b (A0)+, D0 - 0x30d0, // move.w (A0), (A0)+ - 0x3080, // move.w D0, (A0) - 0x3018, // move.w (A0)+, D0 - 0xc040, // and.w D0, D0 - 0x3180, // move.w D0, (A0,D0.w) - 0x1198, // move.b (A0)+, (A0,D0.w) - 0x6501, // bcs $3 - 0x6500, // bcs $2 - 0x6401, // bcc $3 - 0x6a01, // bpl $3 - 0x41f0, // lea (A0,D0.w), A0 - 0x4a28, // tst.b ($0,A0) - 0x0828, // btst #$0, ($0,A0) - 0x0640, // addi.w #$0, D0 - 0x10c0, // move.b D0, (A0)+ - 0x10d8, // move.b (A0)+, (A0)+ -}; -#define hot_opcode_count (int)(sizeof(hot_opcodes) / sizeof(hot_opcodes[0])) - -static int is_op_hot(int op) -{ - int i; - for (i = 0; i < hot_opcode_count; i++) - if (op == hot_opcodes[i]) - return 1; - return 0; -} - -void ot(const char *format, ...) -{ - va_list valist; - int i, len; - - // notaz: stop me from leaving newlines in the middle of format string - // and generating bad code - for(i=0, len=strlen(format); i < len && format[i] != '\n'; i++); - if(i < len-1 && format[len-1] != '\n') printf("\nWARNING: possible improper newline placement:\n%s\n", format); - - if (format[0] == ' ' && format[1] == ' ' && format[2] != ' ' && format[2] != '.') - arm_op_count++; - - va_start(valist,format); - if (AsmFile) vfprintf(AsmFile,format,valist); - va_end(valist); -} - -void ltorg() -{ - if (ms) ot(" LTORG\n"); - else ot(" .ltorg\n"); -} - -#if (CYCLONE_FOR_GENESIS == 2) -// r12=ptr to tas in table, trashes r0,r1 -static void ChangeTAS(int norm) -{ - ot(" ldr r0,=Op4ad0%s\n",norm?"_":""); - ot(" mov r1,#8\n"); - ot("setrtas_loop%i0%s ;@ 4ad0-4ad7\n",norm,ms?"":":"); - ot(" subs r1,r1,#1\n"); - ot(" str r0,[r12],#4\n"); - ot(" bne setrtas_loop%i0\n",norm); - ot(" ldr r0,=Op4ad8%s\n",norm?"_":""); - ot(" mov r1,#7\n"); - ot("setrtas_loop%i1%s ;@ 4ad8-4ade\n",norm,ms?"":":"); - ot(" subs r1,r1,#1\n"); - ot(" str r0,[r12],#4\n"); - ot(" bne setrtas_loop%i1\n",norm); - ot(" ldr r0,=Op4adf%s\n",norm?"_":""); - ot(" str r0,[r12],#4\n"); - ot(" ldr r0,=Op4ae0%s\n",norm?"_":""); - ot(" mov r1,#7\n"); - ot("setrtas_loop%i2%s ;@ 4ae0-4ae6\n",norm,ms?"":":"); - ot(" subs r1,r1,#1\n"); - ot(" str r0,[r12],#4\n"); - ot(" bne setrtas_loop%i2\n",norm); - ot(" ldr r0,=Op4ae7%s\n",norm?"_":""); - ot(" str r0,[r12],#4\n"); - ot(" ldr r0,=Op4ae8%s\n",norm?"_":""); - ot(" mov r1,#8\n"); - ot("setrtas_loop%i3%s ;@ 4ae8-4aef\n",norm,ms?"":":"); - ot(" subs r1,r1,#1\n"); - ot(" str r0,[r12],#4\n"); - ot(" bne setrtas_loop%i3\n",norm); - ot(" ldr r0,=Op4af0%s\n",norm?"_":""); - ot(" mov r1,#8\n"); - ot("setrtas_loop%i4%s ;@ 4af0-4af7\n",norm,ms?"":":"); - ot(" subs r1,r1,#1\n"); - ot(" str r0,[r12],#4\n"); - ot(" bne setrtas_loop%i4\n",norm); - ot(" ldr r0,=Op4af8%s\n",norm?"_":""); - ot(" str r0,[r12],#4\n"); - ot(" ldr r0,=Op4af9%s\n",norm?"_":""); - ot(" str r0,[r12],#4\n"); -} -#endif - -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO -static void AddressErrorWrapper(char rw, const char *dataprg, int iw) -{ - ot("ExceptionAddressError_%c_%s%s\n", rw, dataprg, ms?"":":"); - ot(" ldr r1,[r7,#0x44]\n"); - ot(" mov r6,#0x%02x\n", iw); - ot(" mov r11,r0\n"); - ot(" tst r1,#0x20\n"); - ot(" orrne r6,r6,#4\n"); - ot(" b ExceptionAddressError\n"); - ot("\n"); -} -#endif - -void FlushPC(void) -{ -#if MEMHANDLERS_NEED_PC - if (pc_dirty) - ot(" str r4,[r7,#0x40] ;@ Save PC\n"); -#endif - pc_dirty = 0; -} - -static void PrintFramework() -{ - int state_flags_to_check = 1; // stopped -#if EMULATE_TRACE - state_flags_to_check |= 2; // tracing -#endif -#if EMULATE_HALT - state_flags_to_check |= 0x10; // halted -#endif - - ot(";@ --------------------------- Framework --------------------------\n"); - if (ms) ot("CycloneRun\n"); - else ot("CycloneRun:\n"); - - ot(" stmdb sp!,{r4-r8,r10,r11,lr}\n"); - - ot(" mov r7,r0 ;@ r7 = Pointer to Cpu Context\n"); - ot(" ;@ r0-3 = Temporary registers\n"); - ot(" ldrb r10,[r7,#0x46] ;@ r10 = Flags (NZCV)\n"); - ot(" ldr r6,=CycloneJumpTab ;@ r6 = Opcode Jump table\n"); - ot(" ldr r5,[r7,#0x5c] ;@ r5 = Cycles\n"); - ot(" ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base\n"); - ot(" ;@ r8 = Current Opcode\n"); - ot(" ldr r1,[r7,#0x44] ;@ Get SR high T_S__III and irq level\n"); - ot(" mov r10,r10,lsl #28;@ r10 = Flags 0xf0000000, cpsr format\n"); - ot(" ;@ r11 = Source value / Memory Base\n"); - ot(" str r6,[r7,#0x54] ;@ make a copy to avoid literal pools\n"); - ot("\n"); -#if (CYCLONE_FOR_GENESIS == 2) || EMULATE_TRACE - ot(" mov r2,#0\n"); - ot(" str r2,[r7,#0x98] ;@ clear custom CycloneEnd\n"); -#endif - ot(";@ CheckInterrupt:\n"); - ot(" movs r0,r1,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] - ot(" beq NoInts0\n"); - ot(" cmp r0,#6 ;@ irq>6 ?\n"); - ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); - ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" bgt CycloneDoInterrupt\n"); - ot("NoInts0%s\n", ms?"":":"); - ot("\n"); - ot(";@ Check if our processor is in special state\n"); - ot(";@ and jump to opcode handler if not\n"); - ot(" ldr r0,[r7,#0x58] ;@ state_flags\n"); - ot(" ldrh r8,[r4],#2 ;@ Fetch first opcode\n"); - ot(" tst r0,#0x%02x ;@ special state?\n", state_flags_to_check); - ot(" ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot("\n"); - ot("CycloneSpecial%s\n", ms?"":":"); -#if EMULATE_TRACE - ot(" tst r0,#2 ;@ tracing?\n"); - ot(" bne CycloneDoTrace\n"); -#endif - ot(";@ stopped or halted\n"); - ot(" mov r5,#0\n"); - ot(" str r5,[r7,#0x5C] ;@ eat all cycles\n"); - ot(" ldmia sp!,{r4-r8,r10,r11,pc} ;@ we are stopped, do nothing!\n"); - ot("\n"); - ot("\n"); - - ot(";@ We come back here after execution\n"); - ot("CycloneEnd%s\n", ms?"":":"); - ot(" sub r4,r4,#2\n"); - ot("CycloneEndNoBack%s\n", ms?"":":"); -#if (CYCLONE_FOR_GENESIS == 2) || EMULATE_TRACE - ot(" ldr r1,[r7,#0x98]\n"); - ot(" mov r10,r10,lsr #28\n"); - ot(" tst r1,r1\n"); - ot(" bxne r1 ;@ jump to alternative CycloneEnd\n"); -#else - ot(" mov r10,r10,lsr #28\n"); -#endif - ot(" str r4,[r7,#0x40] ;@ Save Current PC + Memory Base\n"); - ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); - ot(" strb r10,[r7,#0x46] ;@ Save Flags (NZCV)\n"); - ot(" ldmia sp!,{r4-r8,r10,r11,pc}\n"); - ltorg(); - ot("\n"); - ot("\n"); - - ot("CycloneInit%s\n", ms?"":":"); -#if COMPRESS_JUMPTABLE - ot(";@ decompress jump table\n"); - ot(" ldr r12,=CycloneJumpTab\n"); - ot(" add r0,r12,#0xe000*4 ;@ ctrl code pointer\n"); - ot(" ldr r1,[r0,#-4]\n"); - ot(" tst r1,r1\n"); - ot(" movne pc,lr ;@ already uncompressed\n"); - ot(" add r3,r12,#0xa000*4 ;@ handler table pointer, r12=dest\n"); - ot("unc_loop%s\n", ms?"":":"); - ot(" ldrh r1,[r0],#2\n"); - ot(" and r2,r1,#0xf\n"); - ot(" bic r1,r1,#0xf\n"); - ot(" ldr r1,[r3,r1,lsr #2] ;@ r1=handler\n"); - ot(" cmp r2,#0xf\n"); - ot(" addeq r2,r2,#1 ;@ 0xf is really 0x10\n"); - ot(" tst r2,r2\n"); - ot(" ldreqh r2,[r0],#2 ;@ counter is in next word\n"); - ot(" tst r2,r2\n"); - ot(" beq unc_finish ;@ done decompressing\n"); - ot(" tst r1,r1\n"); - ot(" addeq r12,r12,r2,lsl #2 ;@ 0 handler means we should skip those bytes\n"); - ot(" beq unc_loop\n"); - ot("unc_loop_in%s\n", ms?"":":"); - ot(" subs r2,r2,#1\n"); - ot(" str r1,[r12],#4\n"); - ot(" bgt unc_loop_in\n"); - ot(" b unc_loop\n"); - ot("unc_finish%s\n", ms?"":":"); - ot(" ldr r12,=CycloneJumpTab\n"); - ot(" ;@ set a-line and f-line handlers\n"); - ot(" add r0,r12,#0xa000*4\n"); - ot(" ldr r1,[r0,#4] ;@ a-line handler\n"); - ot(" ldr r3,[r0,#8] ;@ f-line handler\n"); - ot(" mov r2,#0x1000\n"); - ot("unc_fill3%s\n", ms?"":":"); - ot(" subs r2,r2,#1\n"); - ot(" str r1,[r0],#4\n"); - ot(" bgt unc_fill3\n"); - ot(" add r0,r12,#0xf000*4\n"); - ot(" mov r2,#0x1000\n"); - ot("unc_fill4%s\n", ms?"":":"); - ot(" subs r2,r2,#1\n"); - ot(" str r3,[r0],#4\n"); - ot(" bgt unc_fill4\n"); - ot(" bx lr\n"); - ltorg(); -#else - ot(";@ do nothing\n"); - ot(" bx lr\n"); -#endif - ot("\n"); - - // -------------- - ot("CycloneReset%s\n", ms?"":":"); - ot(" stmfd sp!,{r7,lr}\n"); - ot(" mov r7,r0\n"); - ot(" mov r0,#0\n"); - ot(" str r0,[r7,#0x58] ;@ state_flags\n"); - ot(" str r0,[r7,#0x48] ;@ OSP\n"); - ot(" mov r1,#0x27 ;@ Supervisor mode\n"); - ot(" strb r1,[r7,#0x44] ;@ set SR high\n"); - ot(" strb r0,[r7,#0x47] ;@ IRQ\n"); - MemHandler(0,2); - ot(" str r0,[r7,#0x3c] ;@ Stack pointer\n"); - ot(" mov r0,#0\n"); - ot(" str r0,[r7,#0x60] ;@ Membase\n"); - ot(" mov r0,#4\n"); - MemHandler(0,2); -#ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); -#else - ot(" mov lr,pc\n"); - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); -#endif - ot(" str r0,[r7,#0x40] ;@ PC + base\n"); - ot(" ldmfd sp!,{r7,pc}\n"); - ot("\n"); - - // -------------- - // 68k: XNZVC, ARM: NZCV - ot("CycloneSetSr%s\n", ms?"":":"); - ot(" mov r2,r1,lsr #8\n"); -// ot(" ldrb r3,[r0,#0x44] ;@ get SR high\n"); -// ot(" eor r3,r3,r2\n"); -// ot(" tst r3,#0x20\n"); -#if EMULATE_TRACE - ot(" and r2,r2,#0xa7 ;@ only defined bits\n"); -#else - ot(" and r2,r2,#0x27 ;@ only defined bits\n"); -#endif - ot(" strb r2,[r0,#0x44] ;@ set SR high\n"); - ot(" mov r2,r1,lsl #25\n"); - ot(" str r2,[r0,#0x4c] ;@ the X flag\n"); - ot(" bic r2,r1,#0xf3\n"); - ot(" tst r1,#1\n"); - ot(" orrne r2,r2,#2\n"); - ot(" tst r1,#2\n"); - ot(" orrne r2,r2,#1\n"); - ot(" strb r2,[r0,#0x46] ;@ flags\n"); - ot(" bx lr\n"); - ot("\n"); - - // -------------- - ot("CycloneGetSr%s\n", ms?"":":"); - ot(" ldrb r1,[r0,#0x46] ;@ flags\n"); - ot(" bic r2,r1,#0xf3\n"); - ot(" tst r1,#1\n"); - ot(" orrne r2,r2,#2\n"); - ot(" tst r1,#2\n"); - ot(" orrne r2,r2,#1\n"); - ot(" ldr r1,[r0,#0x4c] ;@ the X flag\n"); - ot(" tst r1,#0x20000000\n"); - ot(" orrne r2,r2,#0x10\n"); - ot(" ldrb r1,[r0,#0x44] ;@ the SR high\n"); - ot(" orr r0,r2,r1,lsl #8\n"); - ot(" bx lr\n"); - ot("\n"); - - // -------------- - ot("CyclonePack%s\n", ms?"":":"); - ot(" stmfd sp!,{r4,r5,lr}\n"); - ot(" mov r4,r0\n"); - ot(" mov r5,r1\n"); - ot(" mov r3,#16\n"); - ot(";@ 0x00-0x3f: DA registers\n"); - ot("c_pack_loop%s\n",ms?"":":"); - ot(" ldr r1,[r0],#4\n"); - ot(" subs r3,r3,#1\n"); - ot(" str r1,[r5],#4\n"); - ot(" bne c_pack_loop\n"); - ot(";@ 0x40: PC\n"); - ot(" ldr r0,[r4,#0x40] ;@ PC + Memory Base\n"); - ot(" ldr r1,[r4,#0x60] ;@ Memory base\n"); - ot(" sub r0,r0,r1\n"); - ot(" str r0,[r5],#4\n"); - ot(";@ 0x44: SR\n"); - ot(" mov r0,r4\n"); - ot(" bl CycloneGetSr\n"); - ot(" strh r0,[r5],#2\n"); - ot(";@ 0x46: IRQ level\n"); - ot(" ldrb r0,[r4,#0x47]\n"); - ot(" strb r0,[r5],#2\n"); - ot(";@ 0x48: other SP\n"); - ot(" ldr r0,[r4,#0x48]\n"); - ot(" str r0,[r5],#4\n"); - ot(";@ 0x4c: CPU state flags\n"); - ot(" ldr r0,[r4,#0x58]\n"); - ot(" str r0,[r5],#4\n"); - ot(" ldmfd sp!,{r4,r5,pc}\n"); - ot("\n"); - - // -------------- - ot("CycloneUnpack%s\n", ms?"":":"); - ot(" stmfd sp!,{r5,r7,lr}\n"); - ot(" mov r7,r0\n"); - ot(" movs r5,r1\n"); - ot(" beq c_unpack_do_pc\n"); - ot(" mov r3,#16\n"); - ot(";@ 0x00-0x3f: DA registers\n"); - ot("c_unpack_loop%s\n",ms?"":":"); - ot(" ldr r1,[r5],#4\n"); - ot(" subs r3,r3,#1\n"); - ot(" str r1,[r0],#4\n"); - ot(" bne c_unpack_loop\n"); - ot(";@ 0x40: PC\n"); - ot(" ldr r0,[r5],#4 ;@ PC\n"); - ot(" str r0,[r7,#0x40] ;@ handle later\n"); - ot(";@ 0x44: SR\n"); - ot(" ldrh r1,[r5],#2\n"); - ot(" mov r0,r7\n"); - ot(" bl CycloneSetSr\n"); - ot(";@ 0x46: IRQ level\n"); - ot(" ldrb r0,[r5],#2\n"); - ot(" strb r0,[r7,#0x47]\n"); - ot(";@ 0x48: other SP\n"); - ot(" ldr r0,[r5],#4\n"); - ot(" str r0,[r7,#0x48]\n"); - ot(";@ 0x4c: CPU state flags\n"); - ot(" ldr r0,[r5],#4\n"); - ot(" str r0,[r7,#0x58]\n"); - ot("c_unpack_do_pc%s\n",ms?"":":"); - ot(" ldr r0,[r7,#0x40] ;@ unbased PC\n"); -#if USE_CHECKPC_CALLBACK - ot(" mov r1,#0\n"); - ot(" str r1,[r7,#0x60] ;@ Memory base\n"); - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(" mov lr,pc\n"); - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); - #endif -#else - ot(" ldr r1,[r7,#0x60] ;@ Memory base\n"); - ot(" add r0,r0,r1 ;@ r0 = Memory Base + New PC\n"); -#endif - ot(" str r0,[r7,#0x40] ;@ PC + Memory Base\n"); - ot(" ldmfd sp!,{r5,r7,pc}\n"); - ot("\n"); - - // -------------- - ot("CycloneFlushIrq%s\n", ms?"":":"); - ot(" ldr r1,[r0,#0x44] ;@ Get SR high T_S__III and irq level\n"); - ot(" mov r2,r1,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] - ot(" cmp r2,#6 ;@ irq>6 ?\n"); - ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); - ot(" cmple r2,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" movle r0,#0\n"); - ot(" bxle lr ;@ no ints\n"); - ot("\n"); - ot(" stmdb sp!,{r4,r5,r7,r8,r10,r11,lr}\n"); - ot(" mov r7,r0\n"); - ot(" mov r0,r2\n"); - ot(" ldrb r10,[r7,#0x46] ;@ r10 = Flags (NZCV)\n"); - ot(" mov r5,#0\n"); - ot(" ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base\n"); - ot(" mov r10,r10,lsl #28 ;@ r10 = Flags 0xf0000000, cpsr format\n"); - ot(" adr r2,CycloneFlushIrqEnd\n"); - ot(" str r2,[r7,#0x98] ;@ set custom CycloneEnd\n"); - ot(" b CycloneDoInterrupt\n"); - ot("\n"); - ot("CycloneFlushIrqEnd%s\n", ms?"":":"); - ot(" rsb r0,r5,#0\n"); - ot(" str r4,[r7,#0x40] ;@ Save Current PC + Memory Base\n"); - ot(" strb r10,[r7,#0x46] ;@ Save Flags (NZCV)\n"); - ot(" ldmia sp!,{r4,r5,r7,r8,r10,r11,lr}\n"); - ot(" bx lr\n"); - ot("\n"); - ot("\n"); - - // -------------- - ot("CycloneSetRealTAS%s\n", ms?"":":"); -#if (CYCLONE_FOR_GENESIS == 2) - ot(" ldr r12,=CycloneJumpTab\n"); - ot(" tst r0,r0\n"); - ot(" add r12,r12,#0x4a00*4\n"); - ot(" add r12,r12,#0x00d0*4\n"); - ot(" beq setrtas_off\n"); - ChangeTAS(1); - ot(" bx lr\n"); - ot("setrtas_off%s\n",ms?"":":"); - ChangeTAS(0); - ot(" bx lr\n"); - ltorg(); -#else - ot(" bx lr\n"); -#endif - ot("\n"); - - // -------------- - ot(";@ DoInterrupt - r0=IRQ level\n"); - ot("CycloneDoInterruptGoBack%s\n", ms?"":":"); - ot(" sub r4,r4,#2\n"); - ot("CycloneDoInterrupt%s\n", ms?"":":"); - ot(" bic r8,r8,#0xff000000\n"); - ot(" orr r8,r8,r0,lsl #29 ;@ abuse r8\n"); - - // Steps are from "M68000 8-/16-/32-BIT MICROPROCESSORS USER'S MANUAL", p. 6-4 - // but their order is based on http://pasti.fxatari.com/68kdocs/68kPrefetch.html - // 1. Make a temporary copy of the status register and set the status register for exception processing. - ot(" ldr r2,[r7,#0x58] ;@ state flags\n"); - ot(" and r0,r0,#7\n"); - ot(" orr r3,r0,#0x20 ;@ Supervisor mode + IRQ level\n"); - ot(" bic r2,r2,#3 ;@ clear stopped and trace states\n"); -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO - ot(" orr r2,r2,#4 ;@ set activity bit: 'not processing instruction'\n"); -#endif - ot(" str r2,[r7,#0x58]\n"); - ot(" ldrb r6,[r7,#0x44] ;@ Get old SR high, abuse r6\n"); - ot(" strb r3,[r7,#0x44] ;@ Put new SR high\n"); - ot("\n"); - - // 3. Save the current processor context. - ot(" ldr r1,[r7,#0x60] ;@ Get Memory base\n"); - ot(" ldr r11,[r7,#0x3c] ;@ Get A7\n"); - ot(" tst r6,#0x20\n"); - ot(";@ get our SP:\n"); - ot(" ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n"); - ot(" streq r11,[r7,#0x48]\n"); - ot(" moveq r11,r2\n"); - ot(";@ Push old PC onto stack\n"); - ot(" sub r0,r11,#4 ;@ Predecremented A7\n"); - ot(" sub r1,r4,r1 ;@ r1 = Old PC\n"); - MemHandler(1,2); - ot(";@ Push old SR:\n"); - ot(" ldr r0,[r7,#0x4c] ;@ X bit\n"); - ot(" mov r1,r10,lsr #28 ;@ ____NZCV\n"); - ot(" eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n"); - ot(" tst r2,#1 ;@ 1 if C!=V\n"); - ot(" eorne r1,r1,#3 ;@ ____NZVC\n"); - ot(" and r0,r0,#0x20000000\n"); - ot(" orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n"); - ot(" orr r1,r1,r6,lsl #8 ;@ Include old SR high\n"); - ot(" sub r0,r11,#6 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1,0,0); // already checked for address error by prev MemHandler - ot("\n"); - - // 2. Obtain the exception vector. - ot(" mov r11,r8,lsr #29\n"); - ot(" mov r0,r11\n"); -#if USE_INT_ACK_CALLBACK - ot(";@ call IrqCallback if it is defined\n"); -#if INT_ACK_NEEDS_STUFF - ot(" str r4,[r7,#0x40] ;@ Save PC\n"); - ot(" mov r1,r10,lsr #28\n"); - ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n"); - ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); -#endif - ot(" ldr r3,[r7,#0x8c] ;@ IrqCallback\n"); - ot(" add lr,pc,#4*3\n"); - ot(" tst r3,r3\n"); - ot(" streqb r3,[r7,#0x47] ;@ just clear IRQ if there is no callback\n"); - ot(" mvneq r0,#0 ;@ and simulate -1 return\n"); - ot(" bxne r3\n"); -#if INT_ACK_CHANGES_CYCLES - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); -#endif - ot(";@ get IRQ vector address:\n"); - ot(" cmn r0,#1 ;@ returned -1?\n"); - ot(" addeq r0,r11,#0x18 ;@ use autovector then\n"); - ot(" cmn r0,#2 ;@ returned -2?\n"); // should be safe as above add should never result in -2 - ot(" moveq r0,#0x18 ;@ use spurious interrupt then\n"); -#else // !USE_INT_ACK_CALLBACK - ot(";@ Clear irq:\n"); - ot(" mov r2,#0\n"); - ot(" strb r2,[r7,#0x47]\n"); - ot(" add r0,r0,#0x18 ;@ use autovector\n"); -#endif - ot(" mov r0,r0,lsl #2 ;@ get vector address\n"); - ot("\n"); - ot(" ldr r11,[r7,#0x60] ;@ Get Memory base\n"); - ot(";@ Read IRQ Vector:\n"); - MemHandler(0,2,0,0); - ot(" tst r0,r0 ;@ uninitialized int vector?\n"); - ot(" moveq r0,#0x3c\n"); - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bleq %sread32 ;@ Call read32(r0) handler\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(" moveq lr,pc\n"); - ot(" ldreq pc,[r7,#0x70] ;@ Call read32(r0) handler\n"); - #endif -#if USE_CHECKPC_CALLBACK - ot(" add lr,pc,#4\n"); - ot(" add r0,r0,r11 ;@ r0 = Memory Base + New PC\n"); - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); - #endif - #if EMULATE_ADDRESS_ERRORS_JUMP - ot(" mov r4,r0\n"); - #else - ot(" bic r4,r0,#1\n"); - #endif -#else - ot(" add r4,r0,r11 ;@ r4 = Memory Base + New PC\n"); - #if EMULATE_ADDRESS_ERRORS_JUMP - ot(" bic r4,r4,#1\n"); - #endif -#endif - ot("\n"); - - // 4. Obtain a new context and resume instruction processing. - // note: the obtain part was already done in previous steps -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" tst r4,#1\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#endif - ot(" ldr r6,[r7,#0x54]\n"); - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - ot(" subs r5,r5,#44 ;@ Subtract cycles\n"); - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); - ot("\n"); - - // -------------- - // trashes all temp regs - ot("Exception%s\n", ms?"":":"); - ot(" ;@ Cause an Exception - Vector number in r0\n"); - ot(" mov r11,lr ;@ Preserve ARM return address\n"); - ot(" bic r8,r8,#0xff000000\n"); - ot(" orr r8,r8,r0,lsl #24 ;@ abuse r8\n"); - - // 1. Make a temporary copy of the status register and set the status register for exception processing. - ot(" ldr r6,[r7,#0x44] ;@ Get old SR high, abuse r6\n"); - ot(" ldr r2,[r7,#0x58] ;@ state flags\n"); - ot(" and r3,r6,#0x27 ;@ clear trace and unused flags\n"); - ot(" orr r3,r3,#0x20 ;@ set supervisor mode\n"); - ot(" bic r2,r2,#3 ;@ clear stopped and trace states\n"); - ot(" str r2,[r7,#0x58]\n"); - ot(" strb r3,[r7,#0x44] ;@ Put new SR high\n"); - ot("\n"); - - // 3. Save the current processor context. - ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n"); - ot(" tst r6,#0x20\n"); - ot(";@ get our SP:\n"); - ot(" ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n"); - ot(" streq r0,[r7,#0x48]\n"); - ot(" moveq r0,r2\n"); - ot(";@ Push old PC onto stack\n"); - ot(" ldr r1,[r7,#0x60] ;@ Get Memory base\n"); - ot(" sub r0,r0,#4 ;@ Predecremented A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - ot(" sub r1,r4,r1 ;@ r1 = Old PC\n"); - MemHandler(1,2); - ot(";@ Push old SR:\n"); - ot(" ldr r0,[r7,#0x4c] ;@ X bit\n"); - ot(" mov r1,r10,lsr #28 ;@ ____NZCV\n"); - ot(" eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n"); - ot(" tst r2,#1 ;@ 1 if C!=V\n"); - ot(" eorne r1,r1,#3 ;@ ____NZVC\n"); - ot(" and r0,r0,#0x20000000\n"); - ot(" orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n"); - ot(" ldr r0,[r7,#0x3c] ;@ A7\n"); - ot(" orr r1,r1,r6,lsl #8 ;@ Include SR high\n"); - ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1,0,0); - ot("\n"); - - // 2. Obtain the exception vector - ot(";@ Read Exception Vector:\n"); - ot(" mov r0,r8,lsr #24\n"); - ot(" mov r0,r0,lsl #2\n"); - MemHandler(0,2,0,0); - ot(" ldr r3,[r7,#0x60] ;@ Get Memory base\n"); -#if USE_CHECKPC_CALLBACK - ot(" add lr,pc,#4\n"); - ot(" add r0,r0,r3 ;@ r0 = Memory Base + New PC\n"); - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); - #endif - #if EMULATE_ADDRESS_ERRORS_JUMP - ot(" mov r4,r0\n"); - #else - ot(" bic r4,r0,#1\n"); - #endif -#else - ot(" add r4,r0,r3 ;@ r4 = Memory Base + New PC\n"); - #if EMULATE_ADDRESS_ERRORS_JUMP - ot(" bic r4,r4,#1\n"); - #endif -#endif - ot("\n"); - - // 4. Resume execution. -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" tst r4,#1\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#endif - ot(" ldr r6,[r7,#0x54]\n"); - ot(" bx r11 ;@ Return\n"); - ot("\n"); - - // -------------- -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO - // first some wrappers: I see no point inlining this code, - // as it will be executed in really rare cases. - AddressErrorWrapper('r', "data", 0x11); - AddressErrorWrapper('r', "prg", 0x12); - AddressErrorWrapper('w', "data", 0x01); - // there are no program writes - // cpu space is only for bus errors? - ot("ExceptionAddressError_r_prg_r4%s\n", ms?"":":"); - ot(" ldr r1,[r7,#0x44]\n"); - ot(" ldr r3,[r7,#0x60] ;@ Get Memory base\n"); - ot(" mov r6,#0x12\n"); - ot(" sub r11,r4,r3\n"); - ot(" tst r1,#0x20\n"); - ot(" orrne r6,r6,#4\n"); - ot("\n"); - - ot("ExceptionAddressError%s\n", ms?"":":"); - ot(";@ r6 - info word (without instruction/not bit), r11 - faulting address\n"); - - // 1. Make a temporary copy of the status register and set the status register for exception processing. - ot(" ldrb r0,[r7,#0x44] ;@ Get old SR high\n"); - ot(" ldr r2,[r7,#0x58] ;@ state flags\n"); - ot(" and r3,r0,#0x27 ;@ clear trace and unused flags\n"); - ot(" orr r3,r3,#0x20 ;@ set supervisor mode\n"); - ot(" strb r3,[r7,#0x44] ;@ Put new SR high\n"); - ot(" bic r2,r2,#3 ;@ clear stopped and trace states\n"); - ot(" tst r2,#4\n"); - ot(" orrne r6,r6,#8 ;@ complete info word\n"); - ot(" orr r2,r2,#4 ;@ set activity bit: 'not processing instruction'\n"); -#if EMULATE_HALT - ot(" tst r2,#8\n"); - ot(" orrne r2,r2,#0x10 ;@ HALT\n"); - ot(" orr r2,r2,#8 ;@ processing address error\n"); - ot(" str r2,[r7,#0x58]\n"); - ot(" movne r5,#0\n"); - ot(" bne CycloneEndNoBack ;@ bye bye\n"); -#else - ot(" str r2,[r7,#0x58]\n"); -#endif - ot(" and r10,r10,#0xf0000000\n"); - ot(" orr r10,r10,r0,lsl #4 ;@ some preparations for SR push\n"); - ot("\n"); - - // 3. Save the current processor context + additional information. - ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n"); - ot(" tst r10,#0x200\n"); - ot(";@ get our SP:\n"); - ot(" ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n"); - ot(" streq r0,[r7,#0x48]\n"); - ot(" moveq r0,r2\n"); - // PC - ot(";@ Push old PC onto stack\n"); - ot(" ldr r1,[r7,#0x60] ;@ Get Memory base\n"); - ot(" sub r0,r0,#4 ;@ Predecremented A7\n"); - ot(" sub r1,r4,r1 ;@ r1 = Old PC\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,2,0,EMULATE_HALT); - // SR - ot(";@ Push old SR:\n"); - ot(" ldr r0,[r7,#0x4c] ;@ X bit\n"); - ot(" mov r1,r10,ror #28 ;@ ____NZCV\n"); - ot(" eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n"); - ot(" tst r2,#1 ;@ 1 if C!=V\n"); - ot(" eorne r1,r1,#3 ;@ ____NZVC\n"); - ot(" and r0,r0,#0x20000000\n"); - ot(" orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n"); - ot(" ldr r0,[r7,#0x3c] ;@ A7\n"); - ot(" and r10,r10,#0xf0000000\n"); - ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1,0,0); - // IR (instruction register) - ot(";@ Push IR:\n"); - ot(" ldr r0,[r7,#0x3c] ;@ A7\n"); - ot(" mov r1,r8\n"); - ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1,0,0); - // access address - ot(";@ Push address:\n"); - ot(" ldr r0,[r7,#0x3c] ;@ A7\n"); - ot(" mov r1,r11\n"); - ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,2,0,0); - // information word - ot(";@ Push info word:\n"); - ot(" ldr r0,[r7,#0x3c] ;@ A7\n"); - ot(" mov r1,r6\n"); - ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1,0,0); - ot("\n"); - - // 2. Obtain the exception vector - ot(";@ Read Exception Vector:\n"); - ot(" mov r0,#0x0c\n"); - MemHandler(0,2,0,0); - ot(" ldr r3,[r7,#0x60] ;@ Get Memory base\n"); -#if USE_CHECKPC_CALLBACK - ot(" add lr,pc,#4\n"); - ot(" add r0,r0,r3 ;@ r0 = Memory Base + New PC\n"); - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); - #endif - ot(" mov r4,r0\n"); -#else - ot(" add r4,r0,r3 ;@ r4 = Memory Base + New PC\n"); -#endif - ot("\n"); - -#if EMULATE_ADDRESS_ERRORS_JUMP && EMULATE_HALT - ot(" tst r4,#1\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#else - ot(" bic r4,r4,#1\n"); -#endif - - // 4. Resume execution. - ot(" ldr r6,[r7,#0x54]\n"); - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - ot(" subs r5,r5,#50 ;@ Subtract cycles\n"); - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); - ot("\n"); -#endif - - // -------------- -#if EMULATE_TRACE - // expects srh and irq level in r1, next opcode already fetched to r8 - ot("CycloneDoTraceWithChecks%s\n", ms?"":":"); - ot(" ldr r0,[r7,#0x58]\n"); - ot(" cmp r5,#0\n"); - ot(" orr r0,r0,#2 ;@ go to trace mode\n"); - ot(" str r0,[r7,#0x58]\n"); - ot(" blt CycloneEnd\n"); // should take care of situation where we come here when already tracing - ot(";@ CheckInterrupt:\n"); - ot(" movs r0,r1,lsr #24 ;@ Get IRQ level\n"); - ot(" beq CycloneDoTrace\n"); - ot(" cmp r0,#6 ;@ irq>6 ?\n"); - ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); - ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" bgt CycloneDoInterruptGoBack\n"); - ot("\n"); - - // expects next opcode to be already fetched to r8 - ot("CycloneDoTrace%s\n", ms?"":":"); - ot(" str r5,[r7,#0x9c] ;@ save cycles\n"); - ot(" ldr r1,[r7,#0x98]\n"); - ot(" mov r5,#0\n"); - ot(" str r1,[r7,#0xa0]\n"); - ot(" adr r0,TraceEnd\n"); - ot(" str r0,[r7,#0x98] ;@ store TraceEnd as CycloneEnd hadler\n"); - ot(" ldr pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot("\n"); - - ot("TraceEnd%s\n", ms?"":":"); - ot(" ldr r2,[r7,#0x58]\n"); - ot(" ldr r0,[r7,#0x9c] ;@ restore cycles\n"); - ot(" ldr r1,[r7,#0xa0] ;@ old CycloneEnd handler\n"); - ot(" mov r10,r10,lsl #28\n"); - ot(" add r5,r0,r5\n"); - ot(" str r1,[r7,#0x98]\n"); - ot(";@ still tracing?\n"); // exception might have happend - ot(" tst r2,#2\n"); - ot(" beq TraceDisabled\n"); - ot(";@ trace exception\n"); -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO - ot(" ldr r1,[r7,#0x58]\n"); - ot(" mov r0,#9\n"); - ot(" orr r1,r1,#4 ;@ set activity bit: 'not processing instruction'\n"); - ot(" str r1,[r7,#0x58]\n"); -#else - ot(" mov r0,#9\n"); -#endif - ot(" bl Exception\n"); - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - ot(" subs r5,r5,#34 ;@ Subtract cycles\n"); - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); - ot("\n"); - ot("TraceDisabled%s\n", ms?"":":"); - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - ot(" cmp r5,#0\n"); - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); - ot("\n"); -#endif -} - -// --------------------------------------------------------------------------- -// Call Read(r0), Write(r0,r1) or Fetch(r0) -// Trashes r0-r3,r12,lr -int MemHandler(int type,int size,int addrreg,int need_addrerr_check) -{ - int func=0x68+type*0xc+(size<<2); // Find correct offset - char what[32]; - -#if MEMHANDLERS_NEED_FLAGS - ot(" mov r3,r10,lsr #28\n"); - ot(" strb r3,[r7,#0x46] ;@ Save Flags (NZCV)\n"); -#endif - FlushPC(); - -#if (MEMHANDLERS_ADDR_MASK & 0xff000000) - ot(" bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0xff000000); - addrreg=0; -#endif -#if (MEMHANDLERS_ADDR_MASK & 0x00ff0000) - ot(" bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x00ff0000); - addrreg=0; -#endif -#if (MEMHANDLERS_ADDR_MASK & 0x0000ff00) - ot(" bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x0000ff00); - addrreg=0; -#endif -#if (MEMHANDLERS_ADDR_MASK & 0x000000ff) - ot(" bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x000000ff); - addrreg=0; -#endif - -#if EMULATE_ADDRESS_ERRORS_IO - if (size > 0 && need_addrerr_check) - { - ot(" add lr,pc,#4*%i\n", addrreg==0?2:3); // helps to prevent interlocks - if (addrreg != 0) ot(" mov r0,r%i\n", addrreg); - ot(" tst r0,#1 ;@ address error?\n"); - switch (type) { - case 0: ot(" bne ExceptionAddressError_r_data\n"); break; - case 1: ot(" bne ExceptionAddressError_w_data\n"); break; - case 2: ot(" bne ExceptionAddressError_r_prg\n"); break; - } - } - else -#endif - - sprintf(what, "%s%d", type==0 ? "read" : (type==1 ? "write" : "fetch"), 8<>12); fflush(stdout); } // Update progress - - if (!is_op_hot(op)) - OpAny(op); - } - - ot("\n"); - - printf("]\n"); -} - -// helper -static void ott(const char *str, int par, const char *nl, int nlp, int counter, int size) -{ - switch(size) { - case 0: if((counter&7)==0) ot(ms?" dcb ":" .byte "); break; - case 1: if((counter&7)==0) ot(ms?" dcw ":" .hword "); break; - case 2: if((counter&7)==0) ot(ms?" dcd ":" .long "); break; - } - ot(str, par); - if((counter&7)==7) ot(nl,nlp); else ot(","); -} - -static void PrintJumpTable() -{ - int i=0,op=0,len=0; - - ot(";@ -------------------------- Jump Table --------------------------\n"); - - // space for decompressed table - ot(ms?" area |.data|, data\n":" .data\n .align 4\n\n"); - -#if COMPRESS_JUMPTABLE - int handlers=0,reps=0,*indexes,ip,u,out; - // use some weird compression on the jump table - indexes=(int *)malloc(0x10000*4); - if(!indexes) { printf("ERROR: out of memory\n"); exit(1); } - len=0x10000; - - ot("CycloneJumpTab%s\n", ms?"":":"); - if(ms) { - for(i = 0; i < 0xa000/8; i++) - ot(" dcd 0,0,0,0,0,0,0,0\n"); - } else - ot(" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", 0xa000/8); - - // hanlers live in "a-line" part of the table - // first output nop,a-line,f-line handlers - ot(ms?" dcd Op____,Op__al,Op__fl,":" .long Op____,Op__al,Op__fl,"); - handlers=3; - - for(i=0;i=0; u--) if(op == CyJump[u]) break; // already done with this op? - if(u==-1 && op >= 0) { - ott("Op%.4x",op," ;@ %.4x\n",i,handlers,2); - indexes[op] = handlers; - handlers++; - } - } - if(handlers&7) { - fseek(AsmFile, -1, SEEK_CUR); // remove last comma - for(i = 8-(handlers&7); i > 0; i--) - ot(",000000"); - ot("\n"); - } - if(ms) { - for(i = (0x4000-handlers)/8; i > 0; i--) - ot(" dcd 0,0,0,0,0,0,0,0\n"); - } else { - ot(ms?"":" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", (0x4000-handlers)/8); - } - printf("total distinct hanlers: %i\n",handlers); - // output data - for(i=0,ip=0; i < 0xf000; i++, ip++) { - op=CyJump[i]; - if(op == -2) { - // it must skip a-line area, because we keep our data there - ott("0x%.4x", handlers<<4, "\n",0,ip++,1); - ott("0x%.4x", 0x1000, "\n",0,ip,1); - i+=0xfff; - continue; - } - for(reps=1; i < 0xf000; i++, reps++) if(op != CyJump[i+1]) break; - if(op>=0) out=indexes[op]<<4; else out=0; // unrecognised - if(reps <= 0xe || reps==0x10) { - if(reps!=0x10) out|=reps; else out|=0xf; // 0xf means 0x10 (0xf appeared to be unused anyway) - ott("0x%.4x", out, "\n",0,ip,1); - } else { - ott("0x%.4x", out, "\n",0,ip++,1); - ott("0x%.4x", reps,"\n",0,ip,1); - } - } - if(ip&1) ott("0x%.4x", 0, "\n",0,ip++,1); - if(ip&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma - if(ip&7) { - for(i = 8-(ip&7); i > 0; i--) - ot(",0x0000"); - } - ot("\n"); - if(ms) { - for(i = (0x2000-ip/2)/8+1; i > 0; i--) - ot(" dcd 0,0,0,0,0,0,0,0\n"); - } else { - ot(" .rept 0x%x\n .long 0,0,0,0,0,0,0,0\n .endr\n", (0x2000-ip/2)/8+1); - } - ot("\n"); - free(indexes); -#else - ot("CycloneJumpTab%s\n", ms?"":":"); - len=0xfffe; // Hmmm, armasm 2.50.8684 messes up with a 0x10000 long jump table - // notaz: same thing with GNU as 2.9-psion-98r2 (reloc overflow) - // this is due to COFF objects using only 2 bytes for reloc count - - for (i=0;i=0) ott("Op%.4x",op," ;@ %.4x\n",i-7,i,2); - else if(op==-2) ott("Op__al",0, " ;@ %.4x\n",i-7,i,2); - else if(op==-3) ott("Op__fl",0, " ;@ %.4x\n",i-7,i,2); - else ott("Op____",0, " ;@ %.4x\n",i-7,i,2); - } - if(i&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma - - ot("\n"); - ot(";@ notaz: we don't want to crash if we run into those 2 missing opcodes\n"); - ot(";@ so we leave this pattern to patch it later\n"); - ot("%s 0x78563412\n", ms?" dcd":" .long"); - ot("%s 0x56341290\n", ms?" dcd":" .long"); -#endif -} - -static int CycloneMake() -{ - int i; - const char *name="Cyclone.s"; - const char *globl=ms?"export":".global"; - - // Open the assembly file - if (ms) name="Cyclone.asm"; - AsmFile=fopen(name,"wt"); if (AsmFile==NULL) return 1; - - printf("Making %s...\n",name); - - ot("\n;@ Dave's Cyclone 68000 Emulator v%x.%.3x - Assembler Output\n\n",CycloneVer>>12,CycloneVer&0xfff); - - ot(";@ (c) Copyright 2003 Dave, All rights reserved.\n"); - ot(";@ some code (c) Copyright 2005-2007 notaz, All rights reserved.\n"); - ot(";@ Cyclone 68000 is free for non-commercial use.\n\n"); - ot(";@ For commercial use, separate licencing terms must be obtained.\n\n"); - - CyJump=(int *)malloc(0x40000); if (CyJump==NULL) return 1; - memset(CyJump,0xff,0x40000); // Init to -1 - for(i=0xa000; i<0xb000; i++) CyJump[i] = -2; // a-line emulation - for(i=0xf000; i<0x10000; i++) CyJump[i] = -3; // f-line emulation - - ot(ms?" area |.text|, code\n":" .text\n .align 4\n\n"); - ot(" %s CycloneInit\n",globl); - ot(" %s CycloneReset\n",globl); - ot(" %s CycloneRun\n",globl); - ot(" %s CycloneSetSr\n",globl); - ot(" %s CycloneGetSr\n",globl); - ot(" %s CycloneFlushIrq\n",globl); - ot(" %s CyclonePack\n",globl); - ot(" %s CycloneUnpack\n",globl); - ot(" %s CycloneVer\n",globl); -#if (CYCLONE_FOR_GENESIS == 2) - ot(" %s CycloneSetRealTAS\n",globl); - ot(" %s CycloneDoInterrupt\n",globl); - ot(" %s CycloneDoTrace\n",globl); - ot(" %s CycloneJumpTab\n",globl); - ot(" %s Op____\n",globl); - ot(" %s Op6001\n",globl); - ot(" %s Op6601\n",globl); - ot(" %s Op6701\n",globl); -#endif - ot("\n"); - ot(ms?"CycloneVer dcd 0x":"CycloneVer: .long 0x"); - ot("%.4x\n",CycloneVer); - ot("\n"); - - PrintFramework(); - arm_op_count = 0; - PrintOpcodes(); - printf("~%i ARM instructions used for opcode handlers\n", arm_op_count); - PrintJumpTable(); - - if (ms) ot(" END\n"); - - ot("\n\n;@ vim:filetype=armasm\n"); - - fclose(AsmFile); AsmFile=NULL; - -#if 0 - printf("Assembling...\n"); - // Assemble the file - if (ms) system("armasm Cyclone.asm"); - else system("as -o Cyclone.o Cyclone.s"); - printf("Done!\n\n"); -#endif - - free(CyJump); - return 0; -} - -int main() -{ - printf("\n Dave's Cyclone 68000 Emulator v%x.%.3x - Core Creator\n\n",CycloneVer>>12,CycloneVer&0xfff); - - // Make GAS or ARMASM version - CycloneMake(); - return 0; -} - diff --git a/cpu/Cyclone/OpAny.cpp b/cpu/Cyclone/OpAny.cpp deleted file mode 100644 index a50114a..0000000 --- a/cpu/Cyclone/OpAny.cpp +++ /dev/null @@ -1,207 +0,0 @@ - -#include "app.h" - -int opend_op_changes_cycles, opend_check_interrupt, opend_check_trace; - -static unsigned char OpData[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -static unsigned short OpRead16(unsigned int a) -{ - return (unsigned short)( (OpData[a&15]<<8) | OpData[(a+1)&15] ); -} - -// For opcode 'op' use handler 'use' -void OpUse(int op,int use) -{ - char text[64]=""; - CyJump[op]=use; - - if (op!=use) return; - - // Disassemble opcode - DisaPc=0; - DisaText=text; - DisaWord=OpRead16; - - DisaGet(); - ot(";@ ---------- [%.4x] %s uses Op%.4x ----------\n",op,text,use); -} - -void OpStart(int op, int sea, int tea, int op_changes_cycles, int supervisor_check) -{ - int last_op_count=arm_op_count; - - Cycles=0; - OpUse(op,op); // This opcode obviously uses this handler - ot("Op%.4x%s\n", op, ms?"":":"); - - if (supervisor_check) - { - // checks for supervisor bit, if not set, jumps to SuperEnd() - // also sets r11 to SR high value, SuperChange() uses this - ot(" ldr r11,[r7,#0x44] ;@ Get SR high\n"); - } - if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) - { -#if MEMHANDLERS_NEED_PREV_PC - ot(" str r4,[r7,#0x50] ;@ Save prev PC + 2\n"); -#endif -#if MEMHANDLERS_NEED_CYCLES - ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); -#endif - } - if (supervisor_check) - { - ot(" tst r11,#0x20 ;@ Check we are in supervisor mode\n"); - ot(" beq WrongPrivilegeMode ;@ No\n"); - } - if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) { -#if MEMHANDLERS_CHANGE_CYCLES - if (op_changes_cycles) - ot(" mov r5,#0\n"); -#endif - } - if (last_op_count!=arm_op_count) - ot("\n"); - pc_dirty = 1; - opend_op_changes_cycles = opend_check_interrupt = opend_check_trace = 0; -} - -void OpEnd(int sea, int tea) -{ - int did_fetch=0; - opend_check_trace = opend_check_trace && EMULATE_TRACE; -#if MEMHANDLERS_CHANGE_CYCLES - if ((sea >= 0x10 && sea != 0x3c) || (tea >= 0x10 && tea != 0x3c)) - { - if (opend_op_changes_cycles) - { - ot(" ldr r0,[r7,#0x5c] ;@ Load Cycles\n"); - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - ot(" add r5,r0,r5\n"); - did_fetch=1; - } - else - { - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); - } - } -#endif - if (!did_fetch) - ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n"); - if (opend_check_trace) - ot(" ldr r1,[r7,#0x44]\n"); - ot(" subs r5,r5,#%d ;@ Subtract cycles\n",Cycles); - if (opend_check_trace) - { - ot(";@ CheckTrace:\n"); - ot(" tst r1,#0x80\n"); - ot(" bne CycloneDoTraceWithChecks\n"); - ot(" cmp r5,#0\n"); - } - if (opend_check_interrupt) - { - ot(" blt CycloneEnd\n"); - ot(";@ CheckInterrupt:\n"); - if (!opend_check_trace) - ot(" ldr r1,[r7,#0x44]\n"); - ot(" movs r0,r1,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47] - ot(" ldreq pc,[r6,r8,asl #2] ;@ Jump to next opcode handler\n"); - ot(" cmp r0,#6 ;@ irq>6 ?\n"); - ot(" andle r1,r1,#7 ;@ Get interrupt mask\n"); - ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n"); - ot(" ldrle pc,[r6,r8,asl #2] ;@ Jump to next opcode handler\n"); - ot(" b CycloneDoInterruptGoBack\n"); - } - else - { - ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n"); - ot(" b CycloneEnd\n"); - } - ot("\n"); -} - -int OpBase(int op,int size,int sepa) -{ - int ea=op&0x3f; // Get Effective Address - if (ea<0x10) return sepa?(op&~0x7):(op&~0xf); // Use 1 handler for d0-d7 and a0-a7 - if (size==0&&(ea==0x1f || ea==0x27)) return op; // Specific handler for (a7)+ and -(a7) - if (ea<0x38) return op&~7; // Use 1 handler for (a0)-(a7), etc... - return op; -} - -// Get flags, trashes r2 -int OpGetFlags(int subtract,int xbit,int specialz) -{ - if (specialz) ot(" orr r2,r10,#0xb0000000 ;@ for old Z\n"); - - ot(" mrs r10,cpsr ;@ r10=flags\n"); - - if (specialz) ot(" andeq r10,r10,r2 ;@ fix Z\n"); - - if (subtract) ot(" eor r10,r10,#0x20000000 ;@ Invert carry\n"); - - if (xbit) - { - ot(" str r10,[r7,#0x4c] ;@ Save X bit\n"); - } - return 0; -} - -// ----------------------------------------------------------------- - -int g_op; - -void OpAny(int op) -{ - memset(OpData,0x33,sizeof(OpData)); - OpData[0]=(unsigned char)(op>>8); - OpData[1]=(unsigned char)op; - g_op=op; - - if ((op&0xf100)==0x0000) OpArith(op); // + - if ((op&0xc000)==0x0000) OpMove(op); // + - if ((op&0xf5bf)==0x003c) OpArithSr(op); // + Ori/Andi/Eori $nnnn,sr - if ((op&0xf100)==0x0100) OpBtstReg(op); // + - if ((op&0xf138)==0x0108) OpMovep(op); // + - if ((op&0xff00)==0x0800) OpBtstImm(op); // + - if ((op&0xf900)==0x4000) OpNeg(op); // + - if ((op&0xf140)==0x4100) OpChk(op); // + - if ((op&0xf1c0)==0x41c0) OpLea(op); // + - if ((op&0xf9c0)==0x40c0) OpMoveSr(op); // + - if ((op&0xffc0)==0x4800) OpNbcd(op); // + - if ((op&0xfff8)==0x4840) OpSwap(op); // + - if ((op&0xffc0)==0x4840) OpPea(op); // + - if ((op&0xffb8)==0x4880) OpExt(op); // + - if ((op&0xfb80)==0x4880) OpMovem(op); // + - if ((op&0xff00)==0x4a00) OpTst(op); // + - if ((op&0xffc0)==0x4ac0) OpTas(op); // + - if ((op&0xfff0)==0x4e40) OpTrap(op); // + - if ((op&0xfff8)==0x4e50) OpLink(op); // + - if ((op&0xfff8)==0x4e58) OpUnlk(op); // + - if ((op&0xfff0)==0x4e60) OpMoveUsp(op); // + - if ((op&0xfff8)==0x4e70) Op4E70(op); // + Reset/Rts etc - if ((op&0xfffd)==0x4e70) OpStopReset(op);// + - if ((op&0xff80)==0x4e80) OpJsr(op); // + - if ((op&0xf000)==0x5000) OpAddq(op); // + - if ((op&0xf0c0)==0x50c0) OpSet(op); // + - if ((op&0xf0f8)==0x50c8) OpDbra(op); // + - if ((op&0xf000)==0x6000) OpBranch(op); // + - if ((op&0xf100)==0x7000) OpMoveq(op); // + - if ((op&0xa000)==0x8000) OpArithReg(op); // + Or/Sub/And/Add - if ((op&0xb1f0)==0x8100) OpAbcd(op); // + - if ((op&0xb0c0)==0x80c0) OpMul(op); // + - if ((op&0x90c0)==0x90c0) OpAritha(op); // + - if ((op&0xb130)==0x9100) OpAddx(op); // + - if ((op&0xf000)==0xb000) OpCmpEor(op); // + - if ((op&0xf138)==0xb108) OpCmpm(op); // + - if ((op&0xf130)==0xc100) OpExg(op); // + - if ((op&0xf000)==0xe000) OpAsr(op); // + Asr/l/Ror/l etc - if ((op&0xf8c0)==0xe0c0) OpAsrEa(op); // + - - if (op==0xffff) - { - SuperEnd(); - } -} - diff --git a/cpu/Cyclone/OpArith.cpp b/cpu/Cyclone/OpArith.cpp deleted file mode 100644 index c05f5fd..0000000 --- a/cpu/Cyclone/OpArith.cpp +++ /dev/null @@ -1,819 +0,0 @@ - -#include "app.h" - -// --------------------- Opcodes 0x0000+ --------------------- -// Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 ssaaaaaa -int OpArith(int op) -{ - int type=0,size=0; - int sea=0,tea=0; - int use=0; - const char *shiftstr=""; - - // Get source and target EA - type=(op>>9)&7; if (type==4 || type>=7) return 1; - size=(op>>6)&3; if (size>=3) return 1; - sea= 0x003c; - tea=op&0x003f; - - // See if we can do this opcode: - if (EaCanRead(tea,size)==0) return 1; - if (EaCanWrite(tea)==0 || EaAn(tea)) return 1; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op, sea, tea); Cycles=4; - - // imm must be read first - EaCalcReadNoSE(-1,10,sea,size,0); - EaCalcReadNoSE((type!=6)?11:-1,0,tea,size,0x003f); - - if (size<2) shiftstr=(char *)(size?",asl #16":",asl #24"); - if (size<2) ot(" mov r10,r10,asl #%i\n",size?16:24); - - ot(";@ Do arithmetic:\n"); - - if (type==0) ot(" orr r1,r10,r0%s\n",shiftstr); - if (type==1) ot(" and r1,r10,r0%s\n",shiftstr); - if (type==2||type==6) - ot(" rsbs r1,r10,r0%s ;@ Defines NZCV\n",shiftstr); - if (type==3) ot(" adds r1,r10,r0%s ;@ Defines NZCV\n",shiftstr); - if (type==5) ot(" eor r1,r10,r0%s\n",shiftstr); - - if (type<2 || type==5) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5 - - if (type< 2) OpGetFlags(0,0); // Ori/And - if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit - if (type==3) OpGetFlags(0,1); // Add: X-bit - if (type==5) OpGetFlags(0,0); // Eor - if (type==6) OpGetFlags(1,0); // Cmp: Subtract - ot("\n"); - - if (type!=6) - { - EaWrite(11, 1, tea,size,0x003f,1); - } - - // Correct cycles: - if (type==6) - { - if (size>=2 && tea<0x10) Cycles+=2; - } - else - { - if (size>=2) Cycles+=4; - if (tea>=8) Cycles+=4; - if (type==1 && size>=2 && tea<8) Cycles-=2; - } - - OpEnd(sea,tea); - - return 0; -} - -// --------------------- Opcodes 0x5000+ --------------------- -int OpAddq(int op) -{ - // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA) - int num=0,type=0,size=0,ea=0; - int use=0; - char count[16]=""; - int shift=0; - - num =(op>>9)&7; if (num==0) num=8; - type=(op>>8)&1; - size=(op>>6)&3; if (size>=3) return 1; - ea = op&0x3f; - - // See if we can do this opcode: - if (EaCanRead (ea,size)==0) return 1; - if (EaCanWrite(ea) ==0) return 1; - if (size == 0 && EaAn(ea) ) return 1; - - use=OpBase(op,size,1); - - if (num!=8) use|=0x0e00; // If num is not 8, use same handler - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); - Cycles=ea<8?4:8; - if(type==0&&size==1) Cycles=ea<0x10?4:8; - if(size>=2) Cycles=ea<0x10?8:12; - - if (size>0 && (ea&0x38)==0x08) size=2; // addq.w #n,An is also 32-bit - - EaCalcReadNoSE(11,0,ea,size,0x003f); - - shift=32-(8<=0) sprintf(count,"r2,lsr #%d", lsr); - else sprintf(count,"r2,lsl #%d", -lsr); - - ot("\n"); - } - else - { - sprintf(count,"#0x%.4x",8<>12)&5; - rea =(op>> 9)&7; - dir =(op>> 8)&1; // er,re - size=(op>> 6)&3; if (size>=3) return 1; - ea = op&0x3f; - - if (dir && ea<0x10) return 1; // addx/subx opcode - - // See if we can do this opcode: - if (dir==0 && EaCanRead (ea,size)==0) return 1; - if (dir && EaCanWrite(ea)==0) return 1; - if ((size==0||!(type&1))&&EaAn(ea)) return 1; - - use=OpBase(op,size); - use&=~0x0e00; // Use same opcode for Dn - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=4; - - EaCalcReadNoSE(dir?11:-1,0,ea,size,0x003f); - - EaCalcReadNoSE(dir?-1:11,1,rea,size,0x0e00); - - ot(";@ Do arithmetic:\n"); - if (type==0) strop = "orr"; - if (type==1) strop = (char *) (dir ? "subs" : "rsbs"); - if (type==4) strop = "and"; - if (type==5) strop = "adds"; - - if (size==0) asl=",asl #24"; - if (size==1) asl=",asl #16"; - - if (size<2) ot(" mov r0,r0%s\n",asl); - ot(" %s r1,r0,r1%s\n",strop,asl); - - if ((type&1)==0) ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - - OpGetFlags(type==1,type&1); // 1==subtract - ot("\n"); - - ot(";@ Save result:\n"); - if (size<2) ot(" mov r1,r1,asr #%d\n",size?16:24); - if (dir) EaWrite(11, 1, ea,size,0x003f,0,0); - else EaWrite(11, 1,rea,size,0x0e00,0,0); - - if(rea==ea) { - if(ea<8) Cycles=(size>=2)?8:4; else Cycles+=(size>=2)?26:14; - } else if(dir) { - Cycles+=4; - if(size>=2) Cycles+=4; - } else { - if(size>=2) { - Cycles+=2; - if(ea<0x10||ea==0x3c) Cycles+=2; - } - } - - OpEnd(ea); - - return 0; -} - -// --------------------- Opcodes 0x80c0+ --------------------- -int OpMul(int op) -{ - // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA) - int type=0,rea=0,sign=0,ea=0; - int use=0; - - type=(op>>14)&1; // div/mul - rea =(op>> 9)&7; - sign=(op>> 8)&1; - ea = op&0x3f; - - // See if we can do this opcode: - if (EaCanRead(ea,1)==0||EaAn(ea)) return 1; - - use=OpBase(op,1); - use&=~0x0e00; // Use same for all registers - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); - if(type) Cycles=54; - else Cycles=sign?158:140; - - EaCalcReadNoSE(-1,0,ea,1,0x003f); - - EaCalc(11,0x0e00,rea, 2); - EaRead(11, 2,rea, 2,0x0e00); - - ot(" movs r1,r0,asl #16\n"); - - if (type==0) // div - { - // the manual says C is always cleared, but neither Musashi nor FAME do that - //ot(" bic r10,r10,#0x20000000 ;@ always clear C\n"); - ot(" beq divzero%.4x ;@ division by zero\n",op); - ot("\n"); - - if (sign) - { - ot(" mov r12,#0 ;@ r12 = 1 or 2 if the result is negative\n"); - ot(" tst r2,r2\n"); - ot(" orrmi r12,r12,#2\n"); - ot(" rsbmi r2,r2,#0 ;@ Make r2 positive\n"); - ot("\n"); - ot(" movs r0,r1,asr #16\n"); - ot(" orrmi r12,r12,#1\n"); - ot(" rsbmi r0,r0,#0 ;@ Make r0 positive\n"); - ot("\n"); - ot(";@ detect the nasty 0x80000000 / -1 situation\n"); - ot(" mov r3,r2,asr #31\n"); - ot(" eors r3,r3,r1,asr #16\n"); - ot(" beq wrendofop%.4x\n",op); - } - else - { - ot(" mov r0,r1,lsr #16 ;@ use only 16 bits of divisor\n"); - } - - ot("\n"); - ot(";@ Divide r2 by r0\n"); - ot(" mov r3,#0\n"); - ot(" mov r1,r0\n"); - ot("\n"); - ot(";@ Shift up divisor till it's just less than numerator\n"); - ot("Shift%.4x%s\n",op,ms?"":":"); - ot(" cmp r1,r2,lsr #1\n"); - ot(" movls r1,r1,lsl #1\n"); - ot(" bcc Shift%.4x\n",op); - ot("\n"); - - ot("Divide%.4x%s\n",op,ms?"":":"); - ot(" cmp r2,r1\n"); - ot(" adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n"); - ot(" subcs r2,r2,r1\n"); - ot(" teq r1,r0\n"); - ot(" movne r1,r1,lsr #1\n"); - ot(" bne Divide%.4x\n",op); - ot("\n"); - ot(";@r3==quotient,r2==remainder\n"); - - if (sign) - { - // sign correction - ot(" and r1,r12,#1\n"); - ot(" teq r1,r12,lsr #1\n"); - ot(" rsbne r3,r3,#0 ;@ negate if quotient is negative\n"); - ot(" tst r12,#2\n"); - ot(" rsbne r2,r2,#0 ;@ negate the remainder if divident was negative\n"); - ot("\n"); - - // signed overflow check - ot(" mov r1,r3,asl #16\n"); - ot(" cmp r3,r1,asr #16 ;@ signed overflow?\n"); - ot(" orrne r10,r10,#0x10000000 ;@ set overflow flag\n"); - ot(" bne endofop%.4x ;@ overflow!\n",op); - ot("\n"); - ot("wrendofop%.4x%s\n",op,ms?"":":"); - } - else - { - // overflow check - ot(" movs r1,r3,lsr #16 ;@ check for overflow condition\n"); - ot(" orrne r10,r10,#0x10000000 ;@ set overflow flag\n"); - ot(" bne endofop%.4x ;@ overflow!\n",op); - ot("\n"); - } - - ot(" mov r1,r3,lsl #16 ;@ Clip to 16-bits\n"); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - - ot(" mov r1,r1,lsr #16\n"); - ot(" orr r1,r1,r2,lsl #16 ;@ Insert remainder\n"); - } - - if (type==1) - { - ot(";@ Get 16-bit signs right:\n"); - ot(" mov r0,r1,%s #16\n",sign?"asr":"lsr"); - ot(" mov r2,r2,lsl #16\n"); - ot(" mov r2,r2,%s #16\n",sign?"asr":"lsr"); - ot("\n"); - - ot(" mul r1,r2,r0\n"); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - } - ot("\n"); - - EaWrite(11, 1,rea, 2,0x0e00,1); - - if (type==0) ot("endofop%.4x%s\n",op,ms?"":":"); - OpEnd(ea); - - if (type==0) // div - { - ot("divzero%.4x%s\n",op,ms?"":":"); - ot(" mov r0,#5 ;@ Divide by zero\n"); - ot(" bl Exception\n"); - Cycles+=38; - OpEnd(ea); - ot("\n"); - } - - return 0; -} - -// Get X Bit into carry - trashes r2 -int GetXBit(int subtract) -{ - ot(";@ Get X bit:\n"); - ot(" ldr r2,[r7,#0x4c]\n"); - if (subtract) ot(" mvn r2,r2 ;@ Invert it\n"); - ot(" msr cpsr_flg,r2 ;@ Get into Carry\n"); - ot("\n"); - return 0; -} - -// --------------------- Opcodes 0x8100+ --------------------- -// 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad) -int OpAbcd(int op) -{ - int use=0; - int type=0,sea=0,mem=0,dea=0; - - type=(op>>14)&1; // sbcd/abcd - dea =(op>> 9)&7; - mem =(op>> 3)&1; - sea = op &7; - - if (mem) { sea|=0x20; dea|=0x20; } - - use=op&~0x0e07; // Use same opcode for all registers.. - if (sea==0x27) use|=0x0007; // ___x.b -(a7) - if (dea==0x27) use|=0x0e00; // ___x.b -(a7) - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea,dea); Cycles=6; - - if (mem) - { - ot(";@ Get src/dest EA vals\n"); - EaCalc (0,0x000f, sea,0,1); - EaRead (0, 6, sea,0,0x000f,1); - EaCalcReadNoSE(11,0,dea,0,0x0e00); - } - else - { - ot(";@ Get src/dest reg vals\n"); - EaCalcReadNoSE(-1,6,sea,0,0x0007); - EaCalcReadNoSE(11,0,dea,0,0x0e00); - ot(" mov r6,r6,asl #24\n"); - } - ot(" mov r1,r0,asl #24\n\n"); - - ot(" bic r10,r10,#0xb1000000 ;@ clear all flags except old Z\n"); - - if (type) - { - ot(" ldr r0,[r7,#0x4c] ;@ Get X bit\n"); - ot(" mov r3,#0x00f00000\n"); - ot(" and r2,r3,r1,lsr #4\n"); - ot(" tst r0,#0x20000000\n"); - ot(" and r0,r3,r6,lsr #4\n"); - ot(" add r0,r0,r2\n"); - ot(" addne r0,r0,#0x00100000\n"); -// ot(" tst r0,#0x00800000\n"); -// ot(" orreq r10,r10,#0x01000000 ;@ Undefined V behavior\n"); - ot(" cmp r0,#0x00900000\n"); - ot(" addhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); - - ot(" mov r2,r1,lsr #28\n"); - ot(" add r0,r0,r2,lsl #24\n"); - ot(" mov r2,r6,lsr #28\n"); - ot(" add r0,r0,r2,lsl #24\n"); - ot(" cmp r0,#0x09900000\n"); - ot(" orrhi r10,r10,#0x20000000 ;@ C\n"); - ot(" subhi r0,r0,#0x0a000000\n"); -// ot(" and r3,r10,r0,lsr #3 ;@ Undefined V behavior part II\n"); -// ot(" orr r10,r10,r3,lsl #4 ;@ V\n"); - ot(" movs r0,r0,lsl #4\n"); - ot(" orrmi r10,r10,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does - ot(" bicne r10,r10,#0x40000000 ;@ Z flag\n"); - } - else - { - ot(" ldr r0,[r7,#0x4c] ;@ Get X bit\n"); - ot(" mov r3,#0x00f00000\n"); - ot(" and r2,r3,r6,lsr #4\n"); - ot(" tst r0,#0x20000000\n"); - ot(" and r0,r3,r1,lsr #4\n"); - ot(" sub r0,r0,r2\n"); - ot(" subne r0,r0,#0x00100000\n"); -// ot(" tst r0,#0x00800000\n"); -// ot(" orreq r10,r10,#0x01000000 ;@ Undefined V behavior\n"); - ot(" cmp r0,#0x00900000\n"); - ot(" subhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); - - ot(" mov r2,r1,lsr #28\n"); - ot(" add r0,r0,r2,lsl #24\n"); - ot(" mov r2,r6,lsr #28\n"); - ot(" sub r0,r0,r2,lsl #24\n"); - ot(" cmp r0,#0x09900000\n"); - ot(" orrhi r10,r10,#0xa0000000 ;@ N and C\n"); - ot(" addhi r0,r0,#0x0a000000\n"); -// ot(" and r3,r10,r0,lsr #3 ;@ Undefined V behavior part II\n"); -// ot(" orr r10,r10,r3,lsl #4 ;@ V\n"); - ot(" movs r0,r0,lsl #4\n"); -// ot(" orrmi r10,r10,#0x80000000 ;@ Undefined N behavior\n"); - ot(" bicne r10,r10,#0x40000000 ;@ Z flag\n"); - } - - ot(" str r10,[r7,#0x4c] ;@ Save X bit\n"); - ot("\n"); - - EaWrite(11, 0, dea,0,0x0e00,1); - - ot(" ldr r6,[r7,#0x54]\n"); - OpEnd(sea,dea); - - return 0; -} - -// 01001000 00eeeeee - nbcd -int OpNbcd(int op) -{ - int use=0; - int ea=0; - - ea=op&0x3f; - - if(EaCanWrite(ea)==0||EaAn(ea)) return 1; - - use=OpBase(op,0); - if(op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=6; - if(ea >= 8) Cycles+=2; - - EaCalcReadNoSE(6,0,ea,0,0x003f); - - // this is rewrite of Musashi's code - ot(" ldr r2,[r7,#0x4c]\n"); - ot(" bic r10,r10,#0xb0000000 ;@ clear all flags, except Z\n"); - ot(" mov r0,r0,asl #24\n"); - ot(" and r2,r2,#0x20000000\n"); - ot(" add r2,r0,r2,lsr #5 ;@ add X\n"); - ot(" rsb r11,r2,#0x9a000000 ;@ do arithmetic\n"); - - ot(" cmp r11,#0x9a000000\n"); - ot(" beq finish%.4x\n",op); - ot("\n"); - - ot(" mvn r3,r11,lsr #31 ;@ Undefined V behavior\n",op); - ot(" and r2,r11,#0x0f000000\n"); - ot(" cmp r2,#0x0a000000\n"); - ot(" andeq r11,r11,#0xf0000000\n"); - ot(" addeq r11,r11,#0x10000000\n"); - ot(" and r3,r3,r11,lsr #31 ;@ Undefined V behavior part II\n",op); - ot(" movs r1,r11,asr #24\n"); - ot(" bicne r10,r10,#0x40000000 ;@ Z\n"); - ot(" orr r10,r10,r3,lsl #28 ;@ save V\n",op); - ot(" orr r10,r10,#0x20000000 ;@ C\n"); - ot("\n"); - - EaWrite(6, 1, ea,0,0x3f,0,0); - - ot("finish%.4x%s\n",op,ms?"":":"); - ot(" tst r11,r11\n"); - ot(" orrmi r10,r10,#0x80000000 ;@ N\n"); - ot(" str r10,[r7,#0x4c] ;@ Save X\n"); - ot("\n"); - - ot(" ldr r6,[r7,#0x54]\n"); - OpEnd(ea); - - return 0; -} - -// --------------------- Opcodes 0x90c0+ --------------------- -// Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA) -int OpAritha(int op) -{ - int use=0; - int type=0,size=0,sea=0,dea=0; - const char *asr=""; - - // Suba/Cmpa/Adda/(invalid): - type=(op>>13)&3; if (type>=3) return 1; - - size=(op>>8)&1; size++; - dea=(op>>9)&7; dea|=8; // Dest=An - sea=op&0x003f; // Source - - // See if we can do this opcode: - if (EaCanRead(sea,size)==0) return 1; - - use=OpBase(op,size); - use&=~0x0e00; // Use same opcode for An - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea); Cycles=(size==2)?6:8; - if(size==2&&(sea<0x10||sea==0x3c)) Cycles+=2; - if(type==1) Cycles=6; - - // EA calculation order defines how situations like suba.w (A0)+, A0 get handled. - // different emus act differently in this situation, I couldn't fugure which is right behaviour. - //if (type == 1) - { - EaCalcReadNoSE(-1,0,sea,size,0x003f); - EaCalcReadNoSE(type!=1?11:-1,1,dea,2,0x0e00); - } -#if 0 - else - { - EaCalcReadNoSE(type!=1?11:-1,1,dea,2,0x0e00); - EaCalcReadNoSE(-1,0,sea,size,0x003f); - } -#endif - - if (size<2) ot(" mov r0,r0,asl #%d\n\n",size?16:24); - if (size<2) asr=(char *)(size?",asr #16":",asr #24"); - - if (type==0) ot(" sub r1,r1,r0%s\n",asr); - if (type==1) ot(" cmp r1,r0%s ;@ Defines NZCV\n",asr); - if (type==1) OpGetFlags(1,0); // Get Cmp flags - if (type==2) ot(" add r1,r1,r0%s\n",asr); - ot("\n"); - - if (type!=1) EaWrite(11, 1, dea,2,0x0e00); - - OpEnd(sea); - - return 0; -} - -// --------------------- Opcodes 0x9100+ --------------------- -// Emit a Subx/Addx opcode, 1t01ddd1 zz00rsss addx.z Ds,Dd -int OpAddx(int op) -{ - int use=0; - int type=0,size=0,dea=0,sea=0,mem=0; - const char *asl=""; - - type=(op>>14)&1; - dea =(op>> 9)&7; - size=(op>> 6)&3; if (size>=3) return 1; - sea = op&7; - mem =(op>> 3)&1; - - // See if we can do this opcode: - if (EaCanRead(sea,size)==0) return 1; - if (EaCanWrite(dea)==0) return 1; - - if (mem) { sea+=0x20; dea+=0x20; } - - use=op&~0x0e07; // Use same opcode for Dn - if (size==0&&sea==0x27) use|=0x0007; // ___x.b -(a7) - if (size==0&&dea==0x27) use|=0x0e00; // ___x.b -(a7) - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea,dea); Cycles=4; - if(size>=2) Cycles+=4; - if(sea>=0x10) Cycles+=2; - - if (mem) - { - ot(";@ Get src/dest EA vals\n"); - EaCalc (0,0x000f, sea,size,1); - EaRead (0, 6, sea,size,0x000f,1); - EaCalcReadNoSE(11,0,dea,size,0x0e00); - } - else - { - ot(";@ Get src/dest reg vals\n"); - EaCalcReadNoSE(-1,6,sea,size,0x0007); - EaCalcReadNoSE(11,0,dea,size,0x0e00); - if (size<2) ot(" mov r6,r6,asl #%d\n\n",size?16:24); - } - - if (size<2) asl=(char *)(size?",asl #16":",asl #24"); - - ot(";@ Do arithmetic:\n"); - GetXBit(type==0); - - if (type==1 && size<2) - { - ot(";@ Make sure the carry bit will tip the balance:\n"); - ot(" mvn r2,#0\n"); - ot(" orr r6,r6,r2,lsr #%i\n",(size==0)?8:16); - ot("\n"); - } - - if (type==0) ot(" rscs r1,r6,r0%s\n",asl); - if (type==1) ot(" adcs r1,r6,r0%s\n",asl); - ot(" orr r3,r10,#0xb0000000 ;@ for old Z\n"); - OpGetFlags(type==0,1,0); // subtract - if (size<2) { - ot(" movs r2,r1,lsr #%i\n", size?16:24); - ot(" orreq r10,r10,#0x40000000 ;@ add potentially missed Z\n"); - } - ot(" andeq r10,r10,r3 ;@ fix Z\n"); - ot("\n"); - - ot(";@ Save result:\n"); - EaWrite(11, 1, dea,size,0x0e00,1); - - ot(" ldr r6,[r7,#0x54]\n"); - OpEnd(sea,dea); - - return 0; -} - -// --------------------- Opcodes 0xb000+ --------------------- -// Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea) -int OpCmpEor(int op) -{ - int rea=0,eor=0; - int size=0,ea=0,use=0; - const char *asl=""; - - // Get EA and register EA - rea=(op>>9)&7; - eor=(op>>8)&1; - size=(op>>6)&3; if (size>=3) return 1; - ea=op&0x3f; - - if (eor && (ea>>3) == 1) return 1; // not a valid mode for eor - - // See if we can do this opcode: - if (EaCanRead(ea,size)==0) return 1; - if (eor && EaCanWrite(ea)==0) return 1; - if (EaAn(ea)&&(eor||size==0)) return 1; - - use=OpBase(op,size); - use&=~0x0e00; // Use 1 handler for register d0-7 - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=4; - if(eor) { - if(ea>8) Cycles+=4; - if(size>=2) Cycles+=4; - } else { - if(size>=2) Cycles+=2; - } - - ot(";@ Get EA into r11 and value into r0:\n"); - EaCalcReadNoSE(eor?11:-1,0,ea,size,0x003f); - - ot(";@ Get register operand into r1:\n"); - EaCalcReadNoSE(-1,1,rea,size,0x0e00); - - if (size<2) ot(" mov r0,r0,asl #%d\n\n",size?16:24); - if (size<2) asl=(char *)(size?",asl #16":",asl #24"); - - ot(";@ Do arithmetic:\n"); - if (eor==0) ot(" rsbs r1,r0,r1%s\n",asl); - if (eor) - { - ot(" eor r1,r0,r1%s\n",asl); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - } - - OpGetFlags(eor==0,0); // Cmp like subtract - ot("\n"); - - if (eor) EaWrite(11, 1,ea,size,0x003f,1); - - OpEnd(ea); - return 0; -} - -// Emit a Cmpm opcode, 1011ddd1 xx001sss (rrr=Adst, xx=size extension, sss=Asrc) -int OpCmpm(int op) -{ - int size=0,sea=0,dea=0,use=0; - const char *asl=""; - - // get size, get EAs - size=(op>>6)&3; if (size>=3) return 1; - sea=(op&7)|0x18; - dea=(op>>9)&0x3f; - - use=op&~0x0e07; // Use 1 handler for all registers.. - if (size==0&&sea==0x1f) use|=0x0007; // ..except (a7)+ - if (size==0&&dea==0x1f) use|=0x0e00; - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea); Cycles=4; - - ot(";@ Get src operand into r11:\n"); - EaCalc (0,0x0007, sea,size,1); - EaRead (0, 11, sea,size,0x0007,1); - - ot(";@ Get dst operand into r0:\n"); - EaCalcReadNoSE(-1,0,dea,size,0x0e00); - - if (size<2) asl=(char *)(size?",asl #16":",asl #24"); - - ot(" rsbs r0,r11,r0%s\n",asl); - OpGetFlags(1,0); // Cmp like subtract - ot("\n"); - - OpEnd(sea); - return 0; -} - - -// Emit a Chk opcode, 0100ddd1 x0eeeeee (rrr=Dn, x=size extension, eeeeee=ea) -int OpChk(int op) -{ - int rea=0; - int size=0,ea=0,use=0; - - // Get EA and register EA - rea=(op>>9)&7; - if((op>>7)&1) - size=1; // word operation - else size=2; // long - ea=op&0x3f; - - if (EaAn(ea)) return 1; // not a valid mode - if (size!=1) return 1; // 000 variant only supports word - - // See if we can do this opcode: - if (EaCanRead(ea,size)==0) return 1; - - use=OpBase(op,size); - use&=~0x0e00; // Use 1 handler for register d0-7 - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=10; - - ot(";@ Get value into r0:\n"); - EaCalcReadNoSE(-1,0,ea,size,0x003f); - - ot(";@ Get register operand into r1:\n"); - EaCalcReadNoSE(-1,1,rea,size,0x0e00); - - if (size<2) ot(" mov r0,r0,asl #%d\n",size?16:24); - if (size<2) ot(" mov r1,r1,asl #%d\n\n",size?16:24); - - ot(";@ get flags, including undocumented ones\n"); - ot(" and r3,r10,#0x80000000\n"); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - - ot(";@ is reg negative?\n"); - ot(" bmi chktrap%.4x\n",op); - - ot(";@ Do arithmetic:\n"); - ot(" bic r10,r10,#0x80000000 ;@ N\n"); - ot(" cmp r1,r0\n"); - ot(" bgt chktrap%.4x\n",op); - - ot(";@ old N remains\n"); - ot(" orr r10,r10,r3\n"); - OpEnd(ea); - - ot("chktrap%.4x%s ;@ CHK exception:\n",op,ms?"":":"); - ot(" mov r0,#6\n"); - ot(" bl Exception\n"); - Cycles+=40; - OpEnd(ea); - - return 0; -} - diff --git a/cpu/Cyclone/OpBranch.cpp b/cpu/Cyclone/OpBranch.cpp deleted file mode 100644 index 63569da..0000000 --- a/cpu/Cyclone/OpBranch.cpp +++ /dev/null @@ -1,517 +0,0 @@ - -#include "app.h" - -// in/out address in r0, trashes all temp regs -static void CheckPc(void) -{ -#if USE_CHECKPC_CALLBACK - #ifdef MEMHANDLERS_DIRECT_PREFIX - ot(" bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX); - #else - ot(";@ Check Memory Base+pc\n"); - ot(" mov lr,pc\n"); - ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n"); - ot("\n"); - #endif -#endif -} - -// Push 32-bit value in r1 - trashes r0-r3,r12,lr -void OpPush32() -{ - ot(";@ Push r1 onto stack\n"); - ot(" ldr r0,[r7,#0x3c]\n"); - ot(" sub r0,r0,#4 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,2); - ot("\n"); -} - -// Push SR - trashes r0-r3,r12,lr -void OpPushSr(int high) -{ - ot(";@ Push SR:\n"); - OpFlagsToReg(high); - ot(" ldr r0,[r7,#0x3c]\n"); - ot(" sub r0,r0,#2 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,1); - ot("\n"); -} - -// Pop SR - trashes r0-r3 -static void PopSr(int high) -{ - ot(";@ Pop SR:\n"); - ot(" ldr r0,[r7,#0x3c]\n"); - ot(" add r1,r0,#2 ;@ Postincrement A7\n"); - ot(" str r1,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(0,1); - ot("\n"); - OpRegToFlags(high); -} - -// Pop PC - trashes r0-r3 -static void PopPc() -{ - ot(";@ Pop PC:\n"); - ot(" ldr r0,[r7,#0x3c]\n"); - ot(" add r1,r0,#4 ;@ Postincrement A7\n"); - ot(" str r1,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(0,2); - ot(" ldr r1,[r7,#0x60] ;@ Get Memory base\n"); - ot(" add r0,r0,r1 ;@ Memory Base+PC\n"); - ot("\n"); - CheckPc(); -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" mov r4,r0\n"); -#else - ot(" bic r4,r0,#1\n"); -#endif -} - -int OpTrap(int op) -{ - int use=0; - - use=op&~0xf; - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,0x10); - ot(" and r0,r8,#0xf ;@ Get trap number\n"); - ot(" orr r0,r0,#0x20 ;@ 32+n\n"); - ot(" bl Exception\n"); - ot("\n"); - - Cycles=38; OpEnd(0x10); - - return 0; -} - -// --------------------- Opcodes 0x4e50+ --------------------- -int OpLink(int op) -{ - int use=0,reg; - - use=op&~7; - reg=op&7; - if (reg==7) use=op; - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,0x10); - - if(reg!=7) { - ot(";@ Get An\n"); - EaCalc(11, 7, 8, 2, 1); - EaRead(11, 1, 8, 2, 7, 1); - } - - ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n"); - ot(" sub r0,r0,#4 ;@ A7-=4\n"); - ot(" mov r8,r0 ;@ abuse r8\n"); - if(reg==7) ot(" mov r1,r0\n"); - ot("\n"); - - ot(";@ Write An to Stack\n"); - MemHandler(1,2); - - ot(";@ Save to An\n"); - if(reg!=7) - EaWrite(11,8, 8, 2, 7, 1); - - ot(";@ Get offset:\n"); - EaCalc(0,0,0x3c,1); // abused r8 is ok because of imm EA - EaRead(0,0,0x3c,1,0); - - ot(" add r8,r8,r0 ;@ Add offset to A7\n"); - ot(" str r8,[r7,#0x3c]\n"); - ot("\n"); - - Cycles=16; - OpEnd(0x10); - return 0; -} - -// --------------------- Opcodes 0x4e58+ --------------------- -int OpUnlk(int op) -{ - int use=0; - - use=op&~7; - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,0x10); - - ot(";@ Get An\n"); - EaCalc(11, 0xf, 8, 2, 1); - EaRead(11, 0, 8, 2, 0xf, 1); - - ot(" add r8,r0,#4 ;@ A7+=4, abuse r8\n"); - ot("\n"); - ot(";@ Pop An from stack:\n"); - MemHandler(0,2); - ot("\n"); - ot(" str r8,[r7,#0x3c] ;@ Save A7\n"); - ot("\n"); - ot(";@ An = value from stack:\n"); - EaWrite(11, 0, 8, 2, 7, 1); - - Cycles=12; - OpEnd(0x10); - return 0; -} - -// --------------------- Opcodes 0x4e70+ --------------------- -// 01001110 01110ttt -int Op4E70(int op) -{ - int type=0; - - type=op&7; // reset/nop/stop/rte/rtd/rts/trapv/rtr - - switch (type) - { - case 1: // nop - OpStart(op); - Cycles=4; - OpEnd(); - return 0; - - case 3: // rte - OpStart(op,0x10,0,0,1); Cycles=20; - PopSr(1); - PopPc(); - ot(" ldr r1,[r7,#0x44] ;@ reload SR high\n"); - SuperChange(op,1); -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO || EMULATE_HALT - ot(" ldr r1,[r7,#0x58]\n"); - ot(" bic r1,r1,#0x0c ;@ clear 'not processing instruction' and 'doing addr error' bits\n"); - ot(" str r1,[r7,#0x58]\n"); -#endif -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" tst r4,#1 ;@ address error?\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#endif - opend_check_interrupt = 1; - opend_check_trace = 1; - OpEnd(0x10,0); - return 0; - - case 5: // rts - OpStart(op,0x10); Cycles=16; - PopPc(); -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" tst r4,#1 ;@ address error?\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#endif - OpEnd(0x10); - return 0; - - case 6: // trapv - OpStart(op,0x10,0,1); Cycles=4; - ot(" tst r10,#0x10000000\n"); - ot(" subne r5,r5,#%i\n",34); - ot(" movne r0,#7 ;@ TRAPV exception\n"); - ot(" blne Exception\n"); - opend_op_changes_cycles = 1; - OpEnd(0x10,0); - return 0; - - case 7: // rtr - OpStart(op,0x10); Cycles=20; - PopSr(0); - PopPc(); -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" tst r4,#1 ;@ address error?\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#endif - OpEnd(0x10); - return 0; - - default: - return 1; - } -} - -// --------------------- Opcodes 0x4e80+ --------------------- -// Emit a Jsr/Jmp opcode, 01001110 1meeeeee -int OpJsr(int op) -{ - int use=0; - int sea=0; - - sea=op&0x003f; - - // See if we can do this opcode: - if (EaCanRead(sea,-1)==0) return 1; - - use=OpBase(op,0); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,(op&0x40)?0:0x10); - - ot(" ldr r11,[r7,#0x60] ;@ Get Memory base\n"); - ot("\n"); - EaCalc(12,0x003f,sea,0); - - ot(";@ Jump - Get new PC from r12\n"); - ot(" add r0,r12,r11 ;@ Memory Base + New PC\n"); - ot("\n"); - CheckPc(); - if (!(op&0x40)) - { - ot(" ldr r2,[r7,#0x3c]\n"); - ot(" sub r1,r4,r11 ;@ r1 = Old PC\n"); - } -#if EMULATE_ADDRESS_ERRORS_JUMP - // jsr prefetches next instruction before pushing old PC, - // according to http://pasti.fxatari.com/68kdocs/68kPrefetch.html - ot(" mov r4,r0\n"); - ot(" tst r4,#1 ;@ address error?\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#else - ot(" bic r4,r0,#1\n"); -#endif - - if (!(op&0x40)) - { - ot(";@ Push old PC onto stack\n"); - ot(" sub r0,r2,#4 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - MemHandler(1,2); - } - - Cycles=(op&0x40) ? 4 : 12; - Cycles+=Ea_add_ns((op&0x40) ? g_jmp_cycle_table : g_jsr_cycle_table, sea); - - OpEnd((op&0x40)?0:0x10); - - return 0; -} - -// --------------------- Opcodes 0x50c8+ --------------------- - -// ARM version of 68000 condition codes: -static const char * const Cond[16]= -{ - "", "", "hi","ls","cc","cs","ne","eq", - "vc","vs","pl","mi","ge","lt","gt","le" -}; - -// Emit a Dbra opcode, 0101cccc 11001nnn vv -int OpDbra(int op) -{ - int use=0; - int cc=0; - - use=op&~7; // Use same handler - cc=(op>>8)&15; - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op); - - switch (cc) - { - case 0: // T - case 1: // F - break; - case 2: // hi - ot(" tst r10,#0x60000000 ;@ hi: !C && !Z\n"); - ot(" beq DbraTrue\n\n"); - break; - case 3: // ls - ot(" tst r10,#0x60000000 ;@ ls: C || Z\n"); - ot(" bne DbraTrue\n\n"); - break; - default: - ot(";@ Is the condition true?\n"); - ot(" msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n"); - ot(";@ If so, don't dbra\n"); - ot(" b%s DbraTrue\n\n",Cond[cc]); - break; - } - - if (cc!=0) - { - ot(";@ Decrement Dn.w\n"); - ot(" and r1,r8,#0x0007\n"); - ot(" mov r1,r1,lsl #2\n"); - ot(" ldrsh r0,[r7,r1]\n"); - ot(" sub r0,r0,#1\n"); - ot(" strh r0,[r7,r1]\n"); - ot("\n"); - - ot(";@ Check if Dn.w is -1\n"); - ot(" cmn r0,#1\n"); - -#if (USE_CHECKPC_CALLBACK && USE_CHECKPC_DBRA) || EMULATE_ADDRESS_ERRORS_JUMP - ot(" beq DbraMin1\n"); - ot("\n"); - - ot(";@ Get Branch offset:\n"); - ot(" ldrsh r0,[r4]\n"); - ot(" add r0,r4,r0 ;@ r0 = New PC\n"); - CheckPc(); -#if EMULATE_ADDRESS_ERRORS_JUMP - ot(" mov r4,r0\n"); - ot(" tst r4,#1 ;@ address error?\n"); - ot(" bne ExceptionAddressError_r_prg_r4\n"); -#else - ot(" bic r4,r0,#1\n"); -#endif -#else - ot("\n"); - ot(";@ Get Branch offset:\n"); - ot(" ldrnesh r0,[r4]\n"); - ot(" addeq r4,r4,#2 ;@ Skip branch offset\n"); - ot(" subeq r5,r5,#4 ;@ additional cycles\n"); - ot(" addne r4,r4,r0 ;@ r4 = New PC\n"); - ot(" bic r4,r4,#1\n"); // we do not emulate address errors - ot("\n"); -#endif - Cycles=12-2; - OpEnd(); - } - - //if (cc==0||cc>=2) - if (op==0x50c8) - { - ot(";@ condition true:\n"); - ot("DbraTrue%s\n", ms?"":":"); - ot(" add r4,r4,#2 ;@ Skip branch offset\n"); - ot("\n"); - Cycles=12; - OpEnd(); - } - -#if (USE_CHECKPC_CALLBACK && USE_CHECKPC_DBRA) || EMULATE_ADDRESS_ERRORS_JUMP - if (op==0x51c8) - { - ot(";@ Dn.w is -1:\n"); - ot("DbraMin1%s\n", ms?"":":"); - ot(" add r4,r4,#2 ;@ Skip branch offset\n"); - ot("\n"); - Cycles=12+2; - OpEnd(); - } -#endif - - return 0; -} - -// --------------------- Opcodes 0x6000+ --------------------- -// Emit a Branch opcode 0110cccc nn (cccc=condition) -int OpBranch(int op) -{ - int size=0,use=0,checkpc=0; - int offset=0; - int cc=0; - const char *asr_r11=""; - - offset=(char)(op&0xff); - cc=(op>>8)&15; - - // Special offsets: - if (offset==0) size=1; - if (offset==-1) size=2; - - if (size==2) size=0; // 000 model does not support long displacement - if (size) use=op; // 16-bit or 32-bit - else use=(op&0xff00)+1; // Use same opcode for all 8-bit branches - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - OpStart(op,size?0x10:0); - Cycles=10; // Assume branch taken - - switch (cc) - { - case 0: // T - case 1: // F - break; - case 2: // hi - ot(" tst r10,#0x60000000 ;@ hi: !C && !Z\n"); - ot(" bne BccDontBranch%i\n\n",8<=2&&(op&0xff00)==0x6700) - { - ot("BccDontBranch%i%s\n", 8<>6)&3; // Btst/Bchg/Bclr/Bset - // Get source and target EA - sea=(op>>9)&7; - tea=op&0x003f; - if (tea<0x10) size=2; // For registers, 32-bits - - if ((tea&0x38)==0x08) return 1; // movep - - // See if we can do this opcode: - if (EaCanRead(tea,0)==0) return 1; - if (type>0) - { - if (EaCanWrite(tea)==0) return 1; - } - - use=OpBase(op,size); - use&=~0x0e00; // Use same handler for all registers - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,tea); - - if(type==1||type==3) { - Cycles=8; - } else { - Cycles=type?8:4; - if(size>=2) Cycles+=2; - } - - EaCalcReadNoSE(-1,11,sea,0,0x0e00); - - EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f); - - if (tea>=0x10) - ot(" and r11,r11,#7 ;@ mem - do mod 8\n"); // size always 0 - else ot(" and r11,r11,#31 ;@ reg - do mod 32\n"); // size always 2 - ot("\n"); - - ot(" mov r1,#1\n"); - ot(" tst r0,r1,lsl r11 ;@ Do arithmetic\n"); - ot(" bicne r10,r10,#0x40000000\n"); - ot(" orreq r10,r10,#0x40000000 ;@ Get Z flag\n"); - ot("\n"); - - if (type>0) - { - if (type==1) ot(" eor r1,r0,r1,lsl r11 ;@ Toggle bit\n"); - if (type==2) ot(" bic r1,r0,r1,lsl r11 ;@ Clear bit\n"); - if (type==3) ot(" orr r1,r0,r1,lsl r11 ;@ Set bit\n"); - ot("\n"); - EaWrite(8,1,tea,size,0x003f,0,0); - } - OpEnd(tea); - - return 0; -} - -// --------------------- Opcodes 0x0800+ --------------------- -// Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn -int OpBtstImm(int op) -{ - int type=0,sea=0,tea=0; - int use=0; - int size=0; - - type=(op>>6)&3; - // Get source and target EA - sea= 0x003c; - tea=op&0x003f; - if (tea<0x10) size=2; // For registers, 32-bits - - // See if we can do this opcode: - if (EaCanRead(tea,0)==0||EaAn(tea)||tea==0x3c) return 1; - if (type>0) - { - if (EaCanWrite(tea)==0) return 1; - } - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea,tea); - - ot("\n"); - EaCalcReadNoSE(-1,0,sea,0,0); - ot(" mov r11,#1\n"); - ot(" bic r10,r10,#0x40000000 ;@ Blank Z flag\n"); - if (tea>=0x10) - ot(" and r0,r0,#7 ;@ mem - do mod 8\n"); // size always 0 - else ot(" and r0,r0,#0x1F ;@ reg - do mod 32\n"); // size always 2 - ot(" mov r11,r11,lsl r0 ;@ Make bit mask\n"); - ot("\n"); - - if(type==1||type==3) { - Cycles=12; - } else { - Cycles=type?12:8; - if(size>=2) Cycles+=2; - } - - EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f); - ot(" tst r0,r11 ;@ Do arithmetic\n"); - ot(" orreq r10,r10,#0x40000000 ;@ Get Z flag\n"); - ot("\n"); - - if (type>0) - { - if (type==1) ot(" eor r1,r0,r11 ;@ Toggle bit\n"); - if (type==2) ot(" bic r1,r0,r11 ;@ Clear bit\n"); - if (type==3) ot(" orr r1,r0,r11 ;@ Set bit\n"); - ot("\n"); - EaWrite(8, 1,tea,size,0x003f,0,0); -#if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES - // this is a bit hacky (device handlers might modify cycles) - if (tea==0x38||tea==0x39) - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); -#endif - } - - OpEnd(sea,tea); - - return 0; -} - -// --------------------- Opcodes 0x4000+ --------------------- -int OpNeg(int op) -{ - // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA) - int type=0,size=0,ea=0,use=0; - - type=(op>>9)&3; - ea =op&0x003f; - size=(op>>6)&3; if (size>=3) return 1; - - // See if we can do this opcode: - if (EaCanRead (ea,size)==0||EaAn(ea)) return 1; - if (EaCanWrite(ea )==0) return 1; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=size<2?4:6; - if(ea >= 0x10) Cycles*=2; - - EaCalc (11,0x003f,ea,size,0,0); - - if (type!=1) EaRead (11,0,ea,size,0x003f,0,0); // Don't need to read for 'clr' (or do we, for a dummy read?) - if (type==1) ot("\n"); - - if (type==0) - { - ot(";@ Negx:\n"); - GetXBit(1); - if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); - ot(" rscs r1,r0,#0 ;@ do arithmetic\n"); - ot(" orr r3,r10,#0xb0000000 ;@ for old Z\n"); - OpGetFlags(1,1,0); - if(size!=2) { - ot(" movs r1,r1,asr #%i\n",size?16:24); - ot(" orreq r10,r10,#0x40000000 ;@ possily missed Z\n"); - } - ot(" andeq r10,r10,r3 ;@ fix Z\n"); - ot("\n"); - } - - if (type==1) - { - ot(";@ Clear:\n"); - ot(" mov r1,#0\n"); - ot(" mov r10,#0x40000000 ;@ NZCV=0100\n"); - ot("\n"); - } - - if (type==2) - { - ot(";@ Neg:\n"); - if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); - ot(" rsbs r1,r0,#0\n"); - OpGetFlags(1,1); - if(size!=2) ot(" mov r1,r1,asr #%i\n",size?16:24); - ot("\n"); - } - - if (type==3) - { - ot(";@ Not:\n"); - if(size!=2) { - ot(" mov r0,r0,asl #%i\n",size?16:24); - ot(" mvn r1,r0,asr #%i\n",size?16:24); - } - else - ot(" mvn r1,r0\n"); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - ot("\n"); - } - - if (type==1) eawrite_check_addrerr=1; - EaWrite(11, 1,ea,size,0x003f,0,0); - - OpEnd(ea); - - return 0; -} - -// --------------------- Opcodes 0x4840+ --------------------- -// Swap, 01001000 01000nnn swap Dn -int OpSwap(int op) -{ - int ea=0,use=0; - - ea=op&7; - use=op&~0x0007; // Use same opcode for all An - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op); Cycles=4; - - EaCalc (11,0x0007,ea,2,1); - EaRead (11, 0,ea,2,0x0007,1); - - ot(" mov r1,r0,ror #16\n"); - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - - EaWrite(11, 1,8,2,0x0007,1); - - OpEnd(); - - return 0; -} - -// --------------------- Opcodes 0x4a00+ --------------------- -// Emit a Tst opcode, 01001010 xxeeeeee -int OpTst(int op) -{ - int sea=0; - int size=0,use=0; - - sea=op&0x003f; - size=(op>>6)&3; if (size>=3) return 1; - - // See if we can do this opcode: - if (EaCanWrite(sea)==0||EaAn(sea)) return 1; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea); Cycles=4; - - EaCalc ( 0,0x003f,sea,size,1); - EaRead ( 0, 0,sea,size,0x003f,1); - - ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n"); - ot(" mrs r10,cpsr ;@ r10=flags\n"); - ot("\n"); - - OpEnd(sea); - return 0; -} - -// --------------------- Opcodes 0x4880+ --------------------- -// Emit an Ext opcode, 01001000 1x000nnn -int OpExt(int op) -{ - int ea=0; - int size=0,use=0; - int shift=0; - - ea=op&0x0007; - size=(op>>6)&1; - shift=32-(8<>8)&15; - ea=op&0x003f; - - if ((ea&0x38)==0x08) return 1; // dbra, not scc - - // See if we can do this opcode: - if (EaCanWrite(ea)==0) return 1; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - changed_cycles=ea<8 && cc>=2; - OpStart(op,ea,0,changed_cycles); Cycles=8; - if (ea<8) Cycles=4; - - if (cc) - ot(" mov r1,#0\n"); - - switch (cc) - { - case 0: // T - ot(" mvn r1,#0\n"); - if (ea<8) Cycles+=2; - break; - case 1: // F - break; - case 2: // hi - ot(" tst r10,#0x60000000 ;@ hi: !C && !Z\n"); - ot(" mvneq r1,r1\n"); - if (ea<8) ot(" subeq r5,r5,#2 ;@ Extra cycles\n"); - break; - case 3: // ls - ot(" tst r10,#0x60000000 ;@ ls: C || Z\n"); - ot(" mvnne r1,r1\n"); - if (ea<8) ot(" subne r5,r5,#2 ;@ Extra cycles\n"); - break; - default: - ot(";@ Is the condition true?\n"); - ot(" msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n"); - ot(" mvn%s r1,r1\n",cond[cc]); - if (ea<8) ot(" sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]); - break; - } - - ot("\n"); - - eawrite_check_addrerr=1; - EaCalc (0,0x003f, ea,size,0,0); - EaWrite(0, 1, ea,size,0x003f,0,0); - - opend_op_changes_cycles=changed_cycles; - OpEnd(ea,0); - return 0; -} - -// Emit a Asr/Lsr/Roxr/Ror opcode -static int EmitAsr(int op,int type,int dir,int count,int size,int usereg) -{ - char pct[8]=""; // count - int shift=32-(8<=1) sprintf(pct,"#%d",count); // Fixed count - - if (usereg) - { - ot(";@ Use Dn for count:\n"); - ot(" and r2,r8,#0x0e00\n"); - ot(" ldr r2,[r7,r2,lsr #7]\n"); - ot(" and r2,r2,#63\n"); - ot("\n"); - strcpy(pct,"r2"); - } - else if (count<0) - { - ot(" mov r2,r8,lsr #9 ;@ Get 'n'\n"); - ot(" and r2,r2,#7\n\n"); strcpy(pct,"r2"); - } - - // Take 2*n cycles: - if (count<0) ot(" sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n"); - else Cycles+=count<<1; - - if (type<2) - { - // Asr/Lsr - if (dir==0 && size<2) - { - ot(";@ For shift right, use loworder bits for the operation:\n"); - ot(" mov r0,r0,%s #%d\n",type?"lsr":"asr",32-(8<>9)&7; - dir =(op>>8)&1; - size =(op>>6)&3; - if (size>=3) return 1; // use OpAsrEa() - usereg=(op>>5)&1; - type =(op>>3)&3; - - if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8 - - // Use the same opcode for target registers: - use=op&~0x0007; - - // As long as count is not 8, use the same opcode for all shift counts: - if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; } - if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea,0,count<0); Cycles=size<2?6:8; - - EaCalc(11,0x0007, ea,size,1); - EaRead(11, 0, ea,size,0x0007,1); - - EmitAsr(op,type,dir,count, size,usereg); - - EaWrite(11, 0, ea,size,0x0007,1); - - opend_op_changes_cycles = (count<0); - OpEnd(ea,0); - - return 0; -} - -// Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee -int OpAsrEa(int op) -{ - int use=0,type=0,dir=0,ea=0,size=1; - - type=(op>>9)&3; - dir =(op>>8)&1; - ea = op&0x3f; - - if (ea<0x10) return 1; - // See if we can do this opcode: - if (EaCanRead(ea,0)==0) return 1; - if (EaCanWrite(ea)==0) return 1; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); Cycles=6; // EmitAsr() will add 2 - - EaCalc (11,0x003f,ea,size,1); - EaRead (11, 0,ea,size,0x003f,1); - - EmitAsr(op,type,dir,1,size,0); - - EaWrite(11, 0,ea,size,0x003f,1); - - OpEnd(ea); - return 0; -} - -int OpTas(int op, int gen_special) -{ - int ea=0; - int use=0; - - ea=op&0x003f; - - // See if we can do this opcode: - if (EaCanWrite(ea)==0 || EaAn(ea)) return 1; - - use=OpBase(op,0); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - if (!gen_special) OpStart(op,ea); - else - ot("Op%.4x_%s\n", op, ms?"":":"); - - Cycles=4; - if(ea>=8) Cycles+=10; - - EaCalc (11,0x003f,ea,0,1); - EaRead (11, 1,ea,0,0x003f,1); - - ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); - OpGetFlags(0,0); - ot("\n"); - -#if CYCLONE_FOR_GENESIS - // the original Sega hardware ignores write-back phase (to memory only) - if (ea < 0x10 || gen_special) { -#endif - ot(" orr r1,r1,#0x80000000 ;@ set bit7\n"); - - EaWrite(11, 1,ea,0,0x003f,1); -#if CYCLONE_FOR_GENESIS - } -#endif - - OpEnd(ea); - -#if (CYCLONE_FOR_GENESIS == 2) - if (!gen_special && ea >= 0x10) { - OpTas(op, 1); - } -#endif - - return 0; -} - diff --git a/cpu/Cyclone/OpMove.cpp b/cpu/Cyclone/OpMove.cpp deleted file mode 100644 index 78adae5..0000000 --- a/cpu/Cyclone/OpMove.cpp +++ /dev/null @@ -1,685 +0,0 @@ - -#include "app.h" - - -// Pack our flags into r1, in SR/CCR register format -// trashes r0,r2 -void OpFlagsToReg(int high) -{ - ot(" ldr r0,[r7,#0x4c] ;@ X bit\n"); - ot(" mov r1,r10,lsr #28 ;@ ____NZCV\n"); - ot(" eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n"); - ot(" tst r2,#1 ;@ 1 if C!=V\n"); - ot(" eorne r1,r1,#3 ;@ ____NZVC\n"); - ot("\n"); - if (high) ot(" ldrb r2,[r7,#0x44] ;@ Include SR high\n"); - ot(" and r0,r0,#0x20000000\n"); - ot(" orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n"); - if (high) ot(" orr r1,r1,r2,lsl #8\n"); - ot("\n"); -} - -// Convert SR/CRR register in r0 to our flags -// trashes r0,r1 -void OpRegToFlags(int high, int srh_reg) -{ - ot(" eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n"); - ot(" mov r2,r0,lsl #25\n"); - ot(" tst r1,#1 ;@ 1 if C!=V\n"); - ot(" eorne r0,r0,#3 ;@ ___XNZCV\n"); - ot(" str r2,[r7,#0x4c] ;@ Store X bit\n"); - ot(" mov r10,r0,lsl #28 ;@ r10=NZCV...\n"); - - if (high) - { - int mask=EMULATE_TRACE?0xa7:0x27; - ot(" mov r%i,r0,ror #8\n",srh_reg); - ot(" and r%i,r%i,#0x%02x ;@ only take defined bits\n",srh_reg,srh_reg,mask); - ot(" strb r%i,[r7,#0x44] ;@ Store SR high\n",srh_reg); - } - ot("\n"); -} - -void SuperEnd(void) -{ - ot(";@ ----------\n"); - ot(";@ tried execute privileged instruction in user mode\n"); - ot("WrongPrivilegeMode%s\n",ms?"":":"); -#if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO - ot(" ldr r1,[r7,#0x58]\n"); - ot(" sub r4,r4,#2 ;@ last opcode wasn't executed - go back\n"); - ot(" orr r1,r1,#4 ;@ set activity bit: 'not processing instruction'\n"); - ot(" str r1,[r7,#0x58]\n"); -#else - ot(" sub r4,r4,#2 ;@ last opcode wasn't executed - go back\n"); -#endif - ot(" mov r0,#8 ;@ privilege violation\n"); - ot(" bl Exception\n"); - Cycles=34; - OpEnd(0); -} - -// does OSP and A7 swapping if needed -// new or old SR (not the one already in [r7,#0x44]) should be passed in r11 -// uses srh from srh_reg (loads if < 0), trashes r0,r11 -void SuperChange(int op,int srh_reg) -{ - ot(";@ A7 <-> OSP?\n"); - if (srh_reg < 0) { - ot(" ldr r0,[r7,#0x44] ;@ Get other SR high\n"); - srh_reg=0; - } - ot(" eor r0,r%i,r11\n",srh_reg); - ot(" tst r0,#0x20\n"); - ot(" beq no_sp_swap%.4x\n",op); - ot(" ;@ swap OSP and A7:\n"); - ot(" ldr r11,[r7,#0x3C] ;@ Get A7\n"); - ot(" ldr r0, [r7,#0x48] ;@ Get OSP\n"); - ot(" str r11,[r7,#0x48]\n"); - ot(" str r0, [r7,#0x3C]\n"); - ot("no_sp_swap%.4x%s\n", op, ms?"":":"); -} - - - -// --------------------- Opcodes 0x1000+ --------------------- -// Emit a Move opcode, 00xxdddd ddssssss -int OpMove(int op) -{ - int sea=0,tea=0; - int size=0,use=0; - int movea=0; - - // Get source and target EA - sea = op&0x003f; - tea =(op&0x01c0)>>3; - tea|=(op&0x0e00)>>9; - - if (tea>=8 && tea<0x10) movea=1; - - // Find size extension - switch (op&0x3000) - { - default: return 1; - case 0x1000: size=0; break; - case 0x3000: size=1; break; - case 0x2000: size=2; break; - } - - if (size<1 && (movea || EaAn(sea))) return 1; // move.b An,* and movea.b * are invalid - - // See if we can do this opcode: - if (EaCanRead (sea,size)==0) return 1; - if (EaCanWrite(tea )==0) return 1; - - use=OpBase(op,size); - if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7 - - if (tea==0x1f || tea==0x27) use|=0x0e00; // Specific handler for (a7)+ and -(a7) - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea,tea); Cycles=4; - - if (movea==0) - { - EaCalcRead(-1,0,sea,size,0x003f); - ot(" adds r1,r0,#0 ;@ Defines NZ, clears CV\n"); - ot(" mrs r10,cpsr ;@ r10=NZCV flags\n"); - ot("\n"); - } - else - { - EaCalcRead(-1,1,sea,size,0x003f); - size=2; // movea always expands to 32-bits - } - - eawrite_check_addrerr=1; -#if SPLIT_MOVEL_PD - if ((tea&0x38)==0x20 && size==2) { // -(An) - EaCalc (8,0x0e00,tea,size,0,0); - ot(" mov r11,r1\n"); - ot(" add r0,r8,#2\n"); - EaWrite(0, 1,tea,1,0x0e00,0,0); - EaWrite(8, 11,tea,1,0x0e00,1); - } - else -#endif - { - EaCalc (0,0x0e00,tea,size,0,0); - EaWrite(0, 1,tea,size,0x0e00,0,0); - } - -#if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES - // this is a bit hacky (device handlers might modify cycles) - if (tea==0x39||((0x10<=tea&&tea<0x30)&&size>=1)) - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); -#endif - - if((tea&0x38)==0x20) Cycles-=2; // less cycles when dest is -(An) - - OpEnd(sea,tea); - return 0; -} - -// --------------------- Opcodes 0x41c0+ --------------------- -// Emit an Lea opcode, 0100nnn1 11aaaaaa -int OpLea(int op) -{ - int use=0; - int sea=0,tea=0; - - sea= op&0x003f; - tea=(op&0x0e00)>>9; tea|=8; - - if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode - - use=OpBase(op,0); - use&=~0x0e00; // Also use 1 handler for target ?0-7 - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,sea,tea); - - eawrite_check_addrerr=1; - EaCalc (1,0x003f,sea,0); // Lea - EaCalc (0,0x0e00,tea,2); - EaWrite(0, 1,tea,2,0x0e00); - - Cycles=Ea_add_ns(g_lea_cycle_table,sea); - - OpEnd(sea,tea); - - return 0; -} - -// --------------------- Opcodes 0x40c0+ --------------------- -// Move SR opcode, 01000tt0 11aaaaaa move SR -int OpMoveSr(int op) -{ - int type=0,ea=0; - int use=0,size=1; - - type=(op>>9)&3; // from SR, from CCR, to CCR, to SR - ea=op&0x3f; - - if(EaAn(ea)) return 1; // can't use An regs - - switch(type) - { - case 0: - if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode: - break; - - case 1: - return 1; // no such op in 68000 - - case 2: case 3: - if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode: - break; - } - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - // 68000 model allows reading whole SR in user mode (but newer models don't) - OpStart(op,ea,0,0,type==3); - Cycles=12; - if (type==0) Cycles=(ea>=8)?8:6; - - if (type==0 || type==1) - { - eawrite_check_addrerr=1; - OpFlagsToReg(type==0); - EaCalc (0,0x003f,ea,size,0,0); - EaWrite(0, 1,ea,size,0x003f,0,0); - } - - if (type==2 || type==3) - { - EaCalcReadNoSE(-1,0,ea,size,0x003f); - OpRegToFlags(type==3,1); - if (type==3) { - SuperChange(op,1); - opend_check_interrupt = 1; - opend_check_trace = 1; - OpEnd(ea); - return 0; - } - } - - OpEnd(ea); - - return 0; -} - - -// Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100 -int OpArithSr(int op) -{ - int type=0,ea=0; - int use=0,size=0; - int sr_mask=EMULATE_TRACE?0xa7:0x27; - - type=(op>>9)&5; if (type==4) return 1; - size=(op>>6)&1; // ccr or sr? - ea=0x3c; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea,0,0,size!=0); Cycles=16; - - EaCalcRead(-1,0,ea,size,0x003f); - - ot(" eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n"); - ot(" tst r1,#1 ;@ 1 if C!=V\n"); - ot(" eorne r0,r0,#3 ;@ ___XNZCV\n"); - ot(" ldr r2,[r7,#0x4c] ;@ Load old X bit\n"); - - // note: old srh is already in r11 (done by OpStart) - if (type==0) { - ot(" orr r10,r10,r0,lsl #28\n"); - ot(" orr r2,r2,r0,lsl #25 ;@ X bit\n"); - if (size!=0) { - ot(" orr r1,r11,r0,lsr #8\n"); - ot(" and r1,r1,#0x%02x ;@ mask-out unused bits\n",sr_mask); - } - } - if (type==1) { - ot(" and r10,r10,r0,lsl #28\n"); - ot(" and r2,r2,r0,lsl #25 ;@ X bit\n"); - if (size!=0) - ot(" and r1,r11,r0,lsr #8\n"); - } - if (type==5) { - ot(" eor r10,r10,r0,lsl #28\n"); - ot(" eor r2,r2,r0,lsl #25 ;@ X bit\n"); - if (size!=0) { - ot(" eor r1,r11,r0,lsr #8\n"); - ot(" and r1,r1,#0x%02x ;@ mask-out unused bits\n",sr_mask); - } - } - - ot(" str r2,[r7,#0x4c] ;@ Save X bit\n"); - if (size!=0) - ot(" strb r1,[r7,#0x44]\n"); - ot("\n"); - - // we can't enter supervisor mode, nor unmask irqs just by using OR - if (size!=0 && type!=0) { - SuperChange(op,1); - ot("\n"); - opend_check_interrupt = 1; - } - // also can't set trace bit with AND - if (size!=0 && type!=1) - opend_check_trace = 1; - - OpEnd(ea); - - return 0; -} - -// --------------------- Opcodes 0x4850+ --------------------- -// Emit an Pea opcode, 01001000 01aaaaaa -int OpPea(int op) -{ - int use=0; - int ea=0; - - ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode - if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode: - - use=OpBase(op,0); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea); - - ot(" ldr r11,[r7,#0x3c]\n"); - EaCalc (1,0x003f, ea,0); - ot("\n"); - ot(" sub r0,r11,#4 ;@ Predecrement A7\n"); - ot(" str r0,[r7,#0x3c] ;@ Save A7\n"); - ot("\n"); - MemHandler(1,2); // Write 32-bit - ot("\n"); - - Cycles=6+Ea_add_ns(g_pea_cycle_table,ea); - - OpEnd(ea); - - return 0; -} - -// --------------------- Opcodes 0x4880+ --------------------- -// Emit a Movem opcode, 01001d00 1xeeeeee regmask -int OpMovem(int op) -{ - int size=0,ea=0,cea=0,dir=0; - int use=0,decr=0,change=0; - - size=((op>>6)&1)+1; // word, long - ea=op&0x003f; - dir=(op>>10)&1; // Direction (1==ea2reg) - - if (dir) { - if (ea<0x10 || ea>0x3b || (ea&0x38)==0x20) return 1; // Invalid EA - } else { - if (ea<0x10 || ea>0x39 || (ea&0x38)==0x18) return 1; - } - - if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1; - if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr - - cea=ea; if (change) cea=0x10; - - use=OpBase(op,size); - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,ea,0,1); - - ot(" ldrh r11,[r4],#2 ;@ r11=register mask\n"); - ot("\n"); - ot(";@ Get the address into r6:\n"); - EaCalc(6,0x003f,cea,size); - -#if !MEMHANDLERS_NEED_PREV_PC - // must save PC, need a spare register - ot(" str r4,[r7,#0x40] ;@ Save PC\n"); -#endif - - ot(";@ r4=Register Index*4:\n"); - if (decr) ot(" mov r4,#0x40 ;@ order reversed for -(An)\n"); - else ot(" mov r4,#-4\n"); - - ot("\n"); - ot(" tst r11,r11\n"); // sanity check - ot(" beq NoRegs%.4x\n",op); - -#if EMULATE_ADDRESS_ERRORS_IO - ot("\n"); - ot(" tst r6,#1 ;@ address error?\n"); - ot(" movne r0,r6\n"); - ot(" bne ExceptionAddressError_%c_data\n",dir?'r':'w'); -#endif - - ot("\n"); - ot("Movemloop%.4x%s\n",op, ms?"":":"); - ot(" add r4,r4,#%d ;@ r4=Next Register\n",decr?-4:4); - ot(" movs r11,r11,lsr #1\n"); - ot(" bcc Movemloop%.4x\n",op); - ot("\n"); - - if (decr) ot(" sub r6,r6,#%d ;@ Pre-decrement address\n",1<>3)&1; // Direction - use=op&~0x0007; // Use same opcode for all An - - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op,0,0,0,1); Cycles=4; - - if (dir) - { - eawrite_check_addrerr=1; - ot(" ldr r1,[r7,#0x48] ;@ Get from USP\n\n"); - EaCalc (0,0x000f,8,2,1); - EaWrite(0, 1,8,2,0x000f,1); - } - else - { - EaCalc (0,0x000f,8,2,1); - EaRead (0, 0,8,2,0x000f,1); - ot(" str r0,[r7,#0x48] ;@ Put in USP\n\n"); - } - - OpEnd(); - - return 0; -} - -// --------------------- Opcodes 0x7000+ --------------------- -// Emit a Move Quick opcode, 0111nnn0 dddddddd moveq #dd,Dn -int OpMoveq(int op) -{ - int use=0; - - use=op&0xf100; // Use same opcode for all values - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op); Cycles=4; - - ot(" movs r0,r8,asl #24\n"); - ot(" and r1,r8,#0x0e00\n"); - ot(" mov r0,r0,asr #24 ;@ Sign extended Quick value\n"); - ot(" mrs r10,cpsr ;@ r10=NZ flags\n"); - ot(" str r0,[r7,r1,lsr #7] ;@ Store into Dn\n"); - ot("\n"); - - OpEnd(); - - return 0; -} - -// --------------------- Opcodes 0xc140+ --------------------- -// Emit a Exchange opcode: -// 1100ttt1 01000sss exg ds,dt -// 1100ttt1 01001sss exg as,at -// 1100ttt1 10001sss exg as,dt -int OpExg(int op) -{ - int use=0,type=0; - - type=op&0xf8; - - if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode - - use=op&0xf1f8; // Use same opcode for all values - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler - - OpStart(op); Cycles=6; - - ot(" and r2,r8,#0x0e00 ;@ Find T register\n"); - ot(" and r3,r8,#0x000f ;@ Find S register\n"); - if (type==0x48) ot(" orr r2,r2,#0x1000 ;@ T is an address register\n"); - ot("\n"); - ot(" ldr r0,[r7,r2,lsr #7] ;@ Get T\n"); - ot(" ldr r1,[r7,r3,lsl #2] ;@ Get S\n"); - ot("\n"); - ot(" str r0,[r7,r3,lsl #2] ;@ T->S\n"); - ot(" str r1,[r7,r2,lsr #7] ;@ S->T\n"); - ot("\n"); - - OpEnd(); - - return 0; -} - -// ------------------------- movep ------------------------------- -// 0000ddd1 0z001sss -// 0000sss1 1z001ddd (to mem) -int OpMovep(int op) -{ - int ea=0,rea=0; - int size=1,use=0,dir,aadd=0; - - use=op&0xf1f8; - if (op!=use) { OpUse(op,use); return 0; } // Use existing handler (for all dests, srcs) - - // Get EA - ea = (op&0x0007)|0x28; - rea= (op&0x0e00)>>9; - dir = (op>>7)&1; - - // Find size extension - if(op&0x0040) size=2; - - OpStart(op,ea); - - if(dir) // reg to mem - { - EaCalcReadNoSE(-1,11,rea,size,0x0e00); - - EaCalc(8,0x000f,ea,size); - if(size==2) { // if operand is long - ot(" mov r1,r11,lsr #24 ;@ first byte\n"); - EaWrite(8,1,ea,0,0x000f); // store first byte - ot(" add r0,r8,#%i\n",(aadd+=2)); - ot(" mov r1,r11,lsr #16 ;@ second byte\n"); - EaWrite(0,1,ea,0,0x000f); // store second byte - ot(" add r0,r8,#%i\n",(aadd+=2)); - } else { - ot(" mov r0,r8\n"); - } - ot(" mov r1,r11,lsr #8 ;@ first or third byte\n"); - EaWrite(0,1,ea,0,0x000f); - ot(" add r0,r8,#%i\n",(aadd+=2)); - ot(" and r1,r11,#0xff\n"); - EaWrite(0,1,ea,0,0x000f); - } - else // mem to reg - { - EaCalc(6,0x000f,ea,size,1); - EaRead(6,11,ea,0,0x000f,1); // read first byte - ot(" add r0,r6,#2\n"); - EaRead(0,1,ea,0,0x000f,1); // read second byte - if(size==2) { // if operand is long - ot(" orr r11,r11,r1,lsr #8 ;@ second byte\n"); - ot(" add r0,r6,#4\n"); - EaRead(0,1,ea,0,0x000f,1); - ot(" orr r11,r11,r1,lsr #16 ;@ third byte\n"); - ot(" add r0,r6,#6\n"); - EaRead(0,1,ea,0,0x000f,1); - ot(" orr r1,r11,r1,lsr #24 ;@ fourth byte\n"); - } else { - ot(" orr r1,r11,r1,lsr #8 ;@ second byte\n"); - } - // store the result - EaCalc(0,0x0e00,rea,size,1); - EaWrite(0,1,rea,size,0x0e00,1); - ot(" ldr r6,[r7,#0x54]\n"); - } - - Cycles=(size==2)?24:16; - OpEnd(ea); - - return 0; -} - -// Emit a Stop/Reset opcodes, 01001110 011100t0 imm -int OpStopReset(int op) -{ - int type=(op>>1)&1; // stop/reset - - OpStart(op,0,0,0,1); - - if(type) { - // copy immediate to SR, stop the CPU and eat all remaining cycles. - ot(" ldrh r0,[r4],#2 ;@ Fetch the immediate\n"); - OpRegToFlags(1); - SuperChange(op,0); - - ot("\n"); - - ot(" ldr r0,[r7,#0x58]\n"); - ot(" mov r5,#0 ;@ eat cycles\n"); - ot(" orr r0,r0,#1 ;@ stopped\n"); - ot(" str r0,[r7,#0x58]\n"); - ot("\n"); - - Cycles = 4; - ot("\n"); - } - else - { - Cycles = 132; -#if USE_RESET_CALLBACK - ot(" str r4,[r7,#0x40] ;@ Save PC\n"); - ot(" mov r1,r10,lsr #28\n"); - ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n"); - ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n"); - ot(" ldr r11,[r7,#0x90] ;@ ResetCallback\n"); - ot(" tst r11,r11\n"); - ot(" movne lr,pc\n"); - ot(" bxne r11 ;@ call ResetCallback if it is defined\n"); - ot(" ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n"); - ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n"); - ot(" ldr r4,[r7,#0x40] ;@ Load PC\n"); - ot(" mov r10,r10,lsl #28\n"); - ot("\n"); -#endif - } - - OpEnd(); - - return 0; -} - diff --git a/cpu/Cyclone/app.h b/cpu/Cyclone/app.h deleted file mode 100644 index 5e468c7..0000000 --- a/cpu/Cyclone/app.h +++ /dev/null @@ -1,111 +0,0 @@ - -#include -#include -#include -#include - -#ifndef CONFIG_FILE -#define CONFIG_FILE "config.h" -#endif -#include CONFIG_FILE - -// Disa.c -#include "Disa/Disa.h" - -// Ea.cpp -extern int earead_check_addrerr; -extern int eawrite_check_addrerr; -extern int g_jmp_cycle_table[]; -extern int g_jsr_cycle_table[]; -extern int g_lea_cycle_table[]; -extern int g_pea_cycle_table[]; -extern int g_movem_cycle_table[]; -int Ea_add_ns(int *tab, int ea); // add nonstandard EA cycles -int EaCalc(int a,int mask,int ea,int size,int top=0,int sign_extend=1); // 6 -int EaRead(int a,int v,int ea,int size,int mask,int top=0,int sign_extend=1); // 7 -int EaCalcRead(int r_ea,int r,int ea,int size,int mask,int sign_extend=1); // 6 -int EaCalcReadNoSE(int r_ea,int r,int ea,int size,int mask); -int EaCanRead(int ea,int size); -int EaWrite(int a,int v,int ea,int size,int mask,int top=0,int sign_extend_ea=1); -int EaCanWrite(int ea); -int EaAn(int ea); - -// Main.cpp -extern int *CyJump; // Jump table -extern int ms; // If non-zero, output in Microsoft ARMASM format -extern const char * const Narm[4]; // Normal ARM Extensions for operand sizes 0,1,2 -extern const char * const Sarm[4]; // Sign-extend ARM Extensions for operand sizes 0,1,2 -extern int Cycles; // Current cycles for opcode -extern int pc_dirty; // something changed PC during processing -extern int arm_op_count; // for stats -void ot(const char *format, ...); -void ltorg(); -int MemHandler(int type,int size,int addrreg=0,int need_addrerr_check=1); -void FlushPC(void); - -// OpAny.cpp -extern int g_op; -extern int opend_op_changes_cycles, opend_check_interrupt, opend_check_trace; -int OpGetFlags(int subtract,int xbit,int sprecialz=0); -void OpUse(int op,int use); -void OpStart(int op,int sea=0,int tea=0,int op_changes_cycles=0,int supervisor_check=0); -void OpEnd(int sea=0,int tea=0); -int OpBase(int op,int size,int sepa=0); -void OpAny(int op); - -//---------------------- -// OpArith.cpp -int OpArith(int op); -int OpLea(int op); -int OpAddq(int op); -int OpArithReg(int op); -int OpMul(int op); -int OpAbcd(int op); -int OpNbcd(int op); -int OpAritha(int op); -int OpAddx(int op); -int OpCmpEor(int op); -int OpCmpm(int op); -int OpChk(int op); -int GetXBit(int subtract); - -// OpBranch.cpp -void OpPush32(); -void OpPushSr(int high); -int OpTrap(int op); -int OpLink(int op); -int OpUnlk(int op); -int Op4E70(int op); -int OpJsr(int op); -int OpBranch(int op); -int OpDbra(int op); - -// OpLogic.cpp -int OpBtstReg(int op); -int OpBtstImm(int op); -int OpNeg(int op); -int OpSwap(int op); -int OpTst(int op); -int OpExt(int op); -int OpSet(int op); -int OpAsr(int op); -int OpAsrEa(int op); -int OpTas(int op, int gen_special=0); - -// OpMove.cpp -int OpMove(int op); -int OpLea(int op); -void OpFlagsToReg(int high); -void OpRegToFlags(int high,int srh_reg=0); -int OpMoveSr(int op); -int OpArithSr(int op); -int OpPea(int op); -int OpMovem(int op); -int OpMoveq(int op); -int OpMoveUsp(int op); -int OpExg(int op); -int OpMovep(int op); -int OpStopReset(int op); -void SuperEnd(void); -void SuperChange(int op,int srh_reg=-1); - diff --git a/cpu/Cyclone/config.h b/cpu/Cyclone/config.h deleted file mode 100644 index d73b5b5..0000000 --- a/cpu/Cyclone/config.h +++ /dev/null @@ -1,182 +0,0 @@ - - -/** - * Cyclone 68000 configuration file -**/ - - -/* - * If this option is enabled, Microsoft ARMASM compatible output is generated - * (output file - Cyclone.asm). Otherwise GNU as syntax is used (Cyclone.s). - */ -#define USE_MS_SYNTAX 0 - -/* - * Enable this option if you are going to use Cyclone to emulate Genesis / - * Mega Drive system. As VDP chip in these systems had control of the bus, - * several instructions were acting differently, for example TAS did'n have - * the write-back phase. That will be emulated, if this option is enabled. - */ -#define CYCLONE_FOR_GENESIS 0 - -/* - * This option compresses Cyclone's jumptable. Because of this the executable - * will be smaller and load slightly faster and less relocations will be needed. - * This also fixes the crash problem with 0xfffe and 0xffff opcodes. - * Warning: if you enable this, you MUST call CycloneInit() before calling - * CycloneRun(), or else it will crash. - */ -#define COMPRESS_JUMPTABLE 1 - -/* - * Address mask for memory hadlers. The bits set will be masked out of address - * parameter, which is passed to r/w memory handlers. - * Using 0xff000000 means that only 24 least significant bits should be used. - * Set to 0 if you want to mask unused address bits in the memory handlers yourself. - */ -#define MEMHANDLERS_ADDR_MASK 0 - -/* - * Cyclone keeps the 4 least significant bits of SR, PC+membase and it's cycle - * counter in ARM registers instead of the context for performance reasons. If you for - * any reason need to access them in your memory handlers, enable the options below, - * otherwise disable them to improve performance. - * - * MEMHANDLERS_NEED_PC updates .pc context field with PC value effective at the time - * when memhandler was called (opcode address + 2-10 bytes). - * MEMHANDLERS_NEED_PREV_PC updates .prev_pc context field to currently executed - * opcode address + 2. - * Note that .pc and .prev_pc values are always real pointers to memory, so you must - * subtract .membase to get M68k PC value. - * - * Warning: updating PC in memhandlers is dangerous, as Cyclone may internally - * increment the PC before fetching the next instruction and continue executing - * at wrong location. It's better to wait until Cyclone CycloneRun() finishes. - * - * Warning: if you enable MEMHANDLERS_CHANGE_CYCLES, you must also enable - * MEMHANDLERS_NEED_CYCLES, or else Cyclone will keep reloading the same cycle - * count and this will screw timing (if not cause a deadlock). - */ -#define MEMHANDLERS_NEED_PC 0 -#define MEMHANDLERS_NEED_PREV_PC 0 -#define MEMHANDLERS_NEED_FLAGS 0 -#define MEMHANDLERS_NEED_CYCLES 0 -#define MEMHANDLERS_CHANGE_PC 0 -#define MEMHANDLERS_CHANGE_FLAGS 0 -#define MEMHANDLERS_CHANGE_CYCLES 0 - -/* - * If the following macro is defined, Cyclone no longer calls read*, write*, - * fetch* and checkpc from it's context, it calls these functions directly - * instead, prefixed with prefix selected below. For example, if - * MEMHANDLERS_DIRECT_PREFIX is set to cyclone_, it will call cyclone_read8 - * on byte reads. - * This is to avoid indirect jumps, which are slower. It also saves one ARM - * instruction. - */ -/* MEMHANDLERS_DIRECT_PREFIX "cyclone_" */ - -/* - * If enabled, Cyclone will call .IrqCallback routine from it's context whenever it - * acknowledges an IRQ. IRQ level (.irq) is not cleared automatically, do this in your - * handler if needed. - * This function must either return vector number to use for interrupt exception, - * CYCLONE_INT_ACK_AUTOVECTOR to use autovector (this is the most common case), or - * CYCLONE_INT_ACK_SPURIOUS (least common case). - * If disabled, it simply uses appropriate autovector, clears the IRQ level and - * continues execution. - */ -#define USE_INT_ACK_CALLBACK 0 - -/* - * Enable this if you need old PC, flags or cycles; - * or you change cycles in your IrqCallback function. - */ -#define INT_ACK_NEEDS_STUFF 0 -#define INT_ACK_CHANGES_CYCLES 0 - -/* - * If enabled, .ResetCallback is called from the context, whenever RESET opcode is - * encountered. All context members are valid and can be changed. - * If disabled, RESET opcode acts as an NOP. - */ -#define USE_RESET_CALLBACK 0 - -/* - * If enabled, UnrecognizedCallback is called if an invalid opcode is - * encountered. All context members are valid and can be changed. The handler - * should return zero if you want Cyclone to gererate "Illegal Instruction" - * exception after this, or nonzero if not. In the later case you should change - * the PC by yourself, or else Cyclone will keep executing that opcode all over - * again. - * If disabled, "Illegal Instruction" exception is generated and execution is - * continued. - */ -#define USE_UNRECOGNIZED_CALLBACK 0 - -/* - * This option will also call UnrecognizedCallback for a-line and f-line - * (0xa*** and 0xf***) opcodes the same way as described above, only appropriate - * exceptions will be generated. - */ -#define USE_AFLINE_CALLBACK 0 - -/* - * This makes Cyclone to call checkpc from it's context whenever it changes the PC - * by a large value. It takes and should return the PC value in PC+membase form. - * The flags and cycle counter are not valid in this function. - */ -#define USE_CHECKPC_CALLBACK 1 - -/* - * This determines if checkpc() should be called after jumps when 8 and 16 bit - * displacement values were used. - */ -#define USE_CHECKPC_OFFSETBITS_16 1 -#define USE_CHECKPC_OFFSETBITS_8 0 - -/* - * Call checkpc() after DBcc jumps (which use 16bit displacement). Cyclone prior to - * 0.0087 never did that. - */ -#define USE_CHECKPC_DBRA 0 - -/* - * When this option is enabled Cyclone will do two word writes instead of one - * long write when handling MOVE.L or MOVEM.L with pre-decrementing destination, - * as described in Bart Trzynadlowski's doc (http://www.trzy.org/files/68knotes.txt). - * Enable this if you are emulating a 16 bit system. - */ -#define SPLIT_MOVEL_PD 1 - -/* - * Enable emulation of trace mode. Shouldn't cause any performance decrease, so it - * should be safe to keep this ON. - */ -#define EMULATE_TRACE 1 - -/* - * If enabled, address error exception will be generated if 68k code jumps to an - * odd address. Causes very small performance hit (2 ARM instructions for every - * emulated jump/return/exception in normal case). - * Note: checkpc() must not clear least significant bit of rebased address - * for this to work, as checks are performed after calling checkpc(). - */ -#define EMULATE_ADDRESS_ERRORS_JUMP 1 - -/* - * If enabled, address error exception will be generated if 68k code tries to - * access a word or longword at an odd address. The performance cost is also 2 ARM - * instructions per access (for address error checks). - */ -#define EMULATE_ADDRESS_ERRORS_IO 0 - -/* - * If an address error happens during another address error processing, - * the processor halts until it is reset (catastrophic system failure, as the manual - * states). This option enables halt emulation. - * Note that this might be not desired if it is known that emulated system should - * never reach this state. - */ -#define EMULATE_HALT 0 - diff --git a/cpu/Cyclone/config_mamegp2x.h b/cpu/Cyclone/config_mamegp2x.h deleted file mode 100644 index 253d271..0000000 --- a/cpu/Cyclone/config_mamegp2x.h +++ /dev/null @@ -1,44 +0,0 @@ - - -/** - * Cyclone 68000 configuration file - * - * Used for mamegp2x Cyclone build. - * See config.h in Cyclone directory for option descriptions. -**/ - - -#define USE_MS_SYNTAX 0 -#define CYCLONE_FOR_GENESIS 0 -#define COMPRESS_JUMPTABLE 1 -#define MEMHANDLERS_ADDR_MASK 0xff000000 - -#define MEMHANDLERS_NEED_PC 1 -#define MEMHANDLERS_NEED_PREV_PC 1 -#define MEMHANDLERS_NEED_FLAGS 0 -#define MEMHANDLERS_NEED_CYCLES 1 -#define MEMHANDLERS_CHANGE_PC 0 -#define MEMHANDLERS_CHANGE_FLAGS 0 -#define MEMHANDLERS_CHANGE_CYCLES 1 - -#define USE_INT_ACK_CALLBACK 1 - -#define INT_ACK_NEEDS_STUFF 0 -#define INT_ACK_CHANGES_CYCLES 0 - -#define USE_RESET_CALLBACK 0 -#define USE_UNRECOGNIZED_CALLBACK 0 -#define USE_AFLINE_CALLBACK 0 - -#define USE_CHECKPC_CALLBACK 1 -#define USE_CHECKPC_OFFSETBITS_16 1 -#define USE_CHECKPC_OFFSETBITS_8 0 -#define USE_CHECKPC_DBRA 0 - -#define SPLIT_MOVEL_PD 1 - -#define EMULATE_TRACE 1 -#define EMULATE_ADDRESS_ERRORS_JUMP 1 -#define EMULATE_ADDRESS_ERRORS_IO 0 -#define EMULATE_HALT 0 - diff --git a/cpu/Cyclone/config_uae4all.h b/cpu/Cyclone/config_uae4all.h deleted file mode 100644 index d10a2cb..0000000 --- a/cpu/Cyclone/config_uae4all.h +++ /dev/null @@ -1,44 +0,0 @@ - - -/** - * Cyclone 68000 configuration file - * - * Used for UAE4ALL Cyclone build. - * See config.h in Cyclone directory for option descriptions. -**/ - - -#define USE_MS_SYNTAX 0 -#define CYCLONE_FOR_GENESIS 0 -#define COMPRESS_JUMPTABLE 1 -#define MEMHANDLERS_ADDR_MASK 0 - -#define MEMHANDLERS_NEED_PC 1 -#define MEMHANDLERS_NEED_PREV_PC 0 -#define MEMHANDLERS_NEED_FLAGS 0 -#define MEMHANDLERS_NEED_CYCLES 1 -#define MEMHANDLERS_CHANGE_PC 0 -#define MEMHANDLERS_CHANGE_FLAGS 0 -#define MEMHANDLERS_CHANGE_CYCLES 1 - -#define USE_INT_ACK_CALLBACK 1 - -#define INT_ACK_NEEDS_STUFF 0 -#define INT_ACK_CHANGES_CYCLES 0 - -#define USE_RESET_CALLBACK 0 -#define USE_UNRECOGNIZED_CALLBACK 1 -#define USE_AFLINE_CALLBACK 1 - -#define USE_CHECKPC_CALLBACK 1 -#define USE_CHECKPC_OFFSETBITS_16 1 -#define USE_CHECKPC_OFFSETBITS_8 0 -#define USE_CHECKPC_DBRA 0 - -#define SPLIT_MOVEL_PD 1 - -#define EMULATE_TRACE 1 -#define EMULATE_ADDRESS_ERRORS_JUMP 1 -#define EMULATE_ADDRESS_ERRORS_IO 1 -#define EMULATE_HALT 0 - diff --git a/cpu/Cyclone/epoc/crash_cyclone.bin b/cpu/Cyclone/epoc/crash_cyclone.bin deleted file mode 100644 index 04c6bb2fc692b5566f112c6d93f4217143fc11ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 524 zcmZQz00AZ@AZ9_rATbypnGF-8BFz%Rz#wh`#4nW3Si^w03Wz-*nEf1r4HJXW zaCegBreIfhM+J9RKi6Q-U8Myl@ z_ -#include -#include - - -typedef struct { - unsigned long _dontcare1[4]; - char signature[4]; // 'EPOC' - unsigned long iCpu; // 0x1000 = X86, 0x2000 = ARM, 0x4000 = M*Core - unsigned long iCheckSumCode; // sum of all 32 bit words in .text - unsigned long _dontcare3[5]; - unsigned long iCodeSize; // size of code, import address table, constant data and export dir |+30 - unsigned long _dontcare4[12]; - unsigned long iCodeOffset; // file offset to code section |+64 - unsigned long _dontcare5[2]; - unsigned long iCodeRelocOffset; // relocations for code and const |+70 - unsigned long iDataRelocOffset; // relocations for data - unsigned long iPriority; // priority of this process (EPriorityHigh=450) -} E32ImageHeader; - - -typedef struct { - unsigned long iSize; // size of this relocation section - unsigned long iNumberOfRelocs; // number of relocations in this section -} E32RelocSection; - - -typedef struct { - unsigned long base; - unsigned long size; -} reloc_page_header; - - -// E32Image relocation section consists of a number of pages -// every page has 8 byte header and a number or 16bit relocation entries -// entry format: -// 0x3000 | <12bit_reloc_offset> -// -// if we have page_header.base == 0x1000 and a reloc entry 0x3110, -// it means that 32bit value at offset 0x1110 of .text section -// is relocatable - -int main(int argc, char *argv[]) -{ - FILE *f = 0; - unsigned char pattern[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56 }; - unsigned char *buff, *p; - unsigned long patt_offset; // pattern offset in .text section - unsigned long size = 0, i, symbols, insert_pos, *handler; - unsigned short reloc_entry; - E32ImageHeader *header; - E32RelocSection *reloc_section; - reloc_page_header *reloc_page; - - if(argc != 3) { - printf("usage: %s \n\n", argv[0]); - printf("note: this was written to fix a problem caused by as v.2.9-psion-98r2 and shouldn't be used for anything else.\n", argv[0]); - return 1; - } - - f = fopen(argv[1], "rb+"); - if(!f) { - printf("%s: couldn't open %s\n", argv[0], argv[1]); - return 2; - } - - symbols = atoi(argv[2]); - - // read the file - fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET); - buff = (unsigned char *) malloc(size); - fread(buff,1,size,f); - - header = (E32ImageHeader *) buff; - - if(strncmp(header->signature, "EPOC", 4) || header->iCpu != 0x2000) { - printf("%s: not a E32 executable image for ARM target.\n", argv[0]); - fclose(f); - free(buff); - return 2; - } - - // find the pattern - for(i = 0; i < size-8; i++) - if(memcmp(buff+i, pattern, 8) == 0) break; - if(i == size-8 || i < 4) { - printf("%s: failed to find the pattern.\n", argv[0]); - fclose(f); - free(buff); - return 3; - } - patt_offset = i - header->iCodeOffset; - - // find suitable reloc section - reloc_section = (E32RelocSection *) (buff + header->iCodeRelocOffset); - for(i = 0, p = buff+header->iCodeRelocOffset+8; i < reloc_section->iSize; ) { - reloc_page = (reloc_page_header *) p; - if(patt_offset - reloc_page->base >= 0 && patt_offset - reloc_page->base < 0x1000 - symbols*4) break; - i += reloc_page->size; - p += reloc_page->size; - } - - if(i >= reloc_section->iSize) { - printf("%s: suitable reloc section not found.\n", argv[0]); - fclose(f); - free(buff); - return 4; - } - - // now find the insert pos and update everything - insert_pos = p + reloc_page->size - buff; - reloc_page->size += symbols*2; - reloc_section->iSize += symbols*2; - reloc_section->iNumberOfRelocs += symbols; - header->iDataRelocOffset += symbols*2; // data reloc section is now also pushed a little - header->iPriority = 450; // let's boost our priority :) - - // replace the placeholders themselves - handler = (unsigned long *) (buff + patt_offset + header->iCodeOffset - 4); - for(i = 1; i <= symbols; i++) - *(handler+i) = *handler; - - // recalculate checksum - header->iCheckSumCode = 0; - for(i = 0, p = buff+header->iCodeOffset; i < header->iCodeSize; i+=4, p+=4) - header->iCheckSumCode += *(unsigned long *) p; - - // check for possible padding - if(!*(buff+insert_pos-1)) insert_pos -= 2; - - // write all this joy - fseek(f,0,SEEK_SET); - fwrite(buff, 1, insert_pos, f); - - // write new reloc entries - for(i = 0; i < symbols; i++) { - handler++; - reloc_entry = ((unsigned char *) handler - buff - reloc_page->base - header->iCodeOffset) | 0x3000; - fwrite(&reloc_entry, 1, 2, f); - } - - // write the remaining data - fwrite(buff+insert_pos, 1, size-insert_pos, f); - - // done at last! - fclose(f); - free(buff); - - return 0; -} diff --git a/cpu/Cyclone/epoc/patchtable_symb2.c b/cpu/Cyclone/epoc/patchtable_symb2.c deleted file mode 100644 index 28a1656..0000000 --- a/cpu/Cyclone/epoc/patchtable_symb2.c +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include -#include - -#include - -#define symbols 2 - -int main(int argc, char *argv[]) -{ - FILE *f = 0; - unsigned char pattern[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56 }; - unsigned char *buff, *p; - unsigned long patt_offset; // pattern offset in .text section - unsigned long size = 0, i, insert_pos, *handler;//, symbols; - unsigned short reloc_entry; - IMAGE_BASE_RELOCATION *reloc_page; - IMAGE_DOS_HEADER *dos_header; - IMAGE_FILE_HEADER *file_header; - IMAGE_SECTION_HEADER *sect_header, *relocsect_header = 0, *codesect_header = 0; - - if(argc != 2) { - printf("usage: %s \n\n", argv[0]); - printf("note: this was written to fix a problem related to Cyclone and as v.2.9-psion-98r2 and shouldn't be used for anything else. See Readme.\n", argv[0]); - return 1; - } - - f = fopen(argv[1], "rb+"); - if(!f) { - printf("%s: couldn't open %s\n", argv[0], argv[1]); - return 2; - } - - //symbols = atoi(argv[2]); - - // read the file - fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET); - buff = (unsigned char *) malloc(size); - fread(buff,1,size,f); - - dos_header = (IMAGE_DOS_HEADER *) buff; - file_header= (IMAGE_FILE_HEADER *) (buff+dos_header->e_lfanew+4); - sect_header= (IMAGE_SECTION_HEADER *) (buff+dos_header->e_lfanew+4+sizeof(IMAGE_FILE_HEADER)+sizeof(IMAGE_OPTIONAL_HEADER32)); - - if(size < 0x500 || dos_header->e_magic != IMAGE_DOS_SIGNATURE || - *(DWORD *)(buff+dos_header->e_lfanew) != IMAGE_NT_SIGNATURE || file_header->Machine != 0x0A00) { - printf("%s: not a PE executable image for ARM target.\n", argv[0]); - fclose(f); - free(buff); - return 2; - } - - // scan all sections for data and reloc sections - for(i = 0; i < file_header->NumberOfSections; i++, sect_header++) { - if(strncmp(sect_header->Name, ".text", 5) == 0) codesect_header = sect_header; - else if(strncmp(sect_header->Name, ".reloc", 6) == 0) relocsect_header = sect_header; - } - - if(!codesect_header || !relocsect_header) { - printf("%s: failed to find reloc and/or data section.\n", argv[0]); - fclose(f); - free(buff); - return 3; - } - - if(relocsect_header != sect_header-1) { - printf("%s: bug: reloc section is not last, this is unexpected and not supported.\n", argv[0]); - fclose(f); - free(buff); - return 4; - } - - // find the pattern - for(i = codesect_header->PointerToRawData; i < size-8; i+=2) - if(memcmp(buff+i, pattern, 8) == 0) break; - if(i == size-8 || i < 4) { - printf("%s: failed to find the pattern.\n", argv[0]); - fclose(f); - free(buff); - return 5; - } - - // calculate pattern offset in RVA (relative virtual address) - patt_offset = i - codesect_header->PointerToRawData + codesect_header->VirtualAddress; - - // replace the placeholders themselves - handler = (unsigned long *) (buff + i - 4); - for(i = 1; i <= symbols; i++) - *(handler+i) = *handler; - - // find suitable reloc section - for(i = 0, p = buff+relocsect_header->PointerToRawData; i < relocsect_header->SizeOfRawData; ) { - reloc_page = (IMAGE_BASE_RELOCATION *) p; - if(patt_offset - reloc_page->VirtualAddress >= 0 && patt_offset - reloc_page->VirtualAddress < 0x1000 - symbols*2) break; - i += reloc_page->SizeOfBlock; - p += reloc_page->SizeOfBlock; - } - - if(i >= relocsect_header->SizeOfRawData) { - printf("%s: suitable reloc section not found.\n", argv[0]); - fclose(f); - free(buff); - return 6; - } - - // now find the insert pos and update everything - insert_pos = p + reloc_page->SizeOfBlock - buff; - reloc_page->SizeOfBlock += symbols*2; - relocsect_header->SizeOfRawData += symbols*2; - - // check for possible padding - if(!*(buff+insert_pos-1)) insert_pos -= 2; - - // write all this joy - fseek(f,0,SEEK_SET); - fwrite(buff, 1, insert_pos, f); - - // write new reloc entries - for(i = 0; i < symbols; i++) { - handler++; - reloc_entry = (unsigned short)(((unsigned char *) handler - buff) - reloc_page->VirtualAddress - codesect_header->PointerToRawData + codesect_header->VirtualAddress) | 0x3000; // quite nasty - fwrite(&reloc_entry, 1, 2, f); - } - - // write the remaining data - fwrite(buff+insert_pos, 1, size-insert_pos, f); - - // done at last! - fclose(f); - free(buff); - - return 0; -} diff --git a/cpu/Cyclone/epoc/readme.txt b/cpu/Cyclone/epoc/readme.txt deleted file mode 100644 index 97410f6..0000000 --- a/cpu/Cyclone/epoc/readme.txt +++ /dev/null @@ -1,42 +0,0 @@ -*update* -Use the "compress jumtable" Cyclone config.h option to fix this issue -(no patcher will be needed then). - - -There is a problem with Cyclone on symbian platform: -GNU as generates COFF object files, which allow max of 0xFFFF (65535) relocation -entries. Cyclone uses a jumptable of 0x10000 (65536, 1 for every opcode-word) -antries. When the executable is loaded, all jumptable entries must be relocated -to point to right code location. Because of this limitation, Cyclone's jumptable is -incomplete (misses 2 entries), and if M68k opcodes 0xFFFE or 0xFFFF are ever -encoundered when emulating, your emulator will crash. - -I have written a little patcher to fix that. It writes those two missing entries and -marks them as relocatable. Placeholders must not be deleted just after the jumttable -in the Cyclone source code. - -This version works with intermediate PE executable, which is used both for APPs and EXEs, -and is produced by gcc toolkit just before running petran. So it's best to insert -this in your makefile, in the rule which builds your APP/EXE, just after last 'ld' -statement, for example: - -$(EPOCTRGUREL)\PICODRIVEN.APP : $(EPOCBLDUREL)\PICODRIVEN.in $(EPOCSTATLINKUREL)\EDLL.LIB $(LIBSUREL) - ... - ld -s -e _E32Dll -u _E32Dll --dll \ - "$(EPOCBLDUREL)\PICODRIVEN.exp" \ - -Map "$(EPOCTRGUREL)\PICODRIVEN.APP.map" -o "$(EPOCBLDUREL)\PICODRIVEN.APP" \ - "$(EPOCSTATLINKUREL)\EDLL.LIB" --whole-archive "$(EPOCBLDUREL)\PICODRIVEN.in" \ - --no-whole-archive $(LIBSUREL) $(USERLDFLAGS) - -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.exp" - - patchtable_symb2 "$(EPOCBLDUREL)\PICODRIVEN.APP" - - petran "$(EPOCBLDUREL)\PICODRIVEN.APP" "$@" \ - -nocall -uid1 0x10000079 -uid2 0x100039ce -uid3 0x1000c193 - -$(ERASE) "$(EPOCBLDUREL)\PICODRIVEN.APP" - perl -S ecopyfile.pl "$@" "PICODRIVEN.APP" - - -This is also compatible with ECompXL. - -To test if this thing worked, you can load crash_cyclone.bin in your emulator. diff --git a/cpu/Cyclone/proj/Makefile b/cpu/Cyclone/proj/Makefile deleted file mode 100644 index 55e4486..0000000 --- a/cpu/Cyclone/proj/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -CFLAGS = -Wall -ifdef CONFIG_FILE -CFLAGS += -DCONFIG_FILE=\"$(CONFIG_FILE)\" -endif - -all : cyclone.s - -cyclone.s : Cyclone.exe - ./Cyclone.exe - -Cyclone.exe : Main.o Ea.o OpAny.o OpArith.o OpBranch.o OpLogic.o Disa.o OpMove.o - $(CC) $^ -o $@ -lstdc++ - -Main.o : ../Main.cpp ../app.h - $(CC) $(CFLAGS) ../Main.cpp -c -o $@ - -Ea.o : ../Ea.cpp ../app.h - $(CC) $(CFLAGS) ../Ea.cpp -c -o $@ - -OpAny.o : ../OpAny.cpp ../app.h - $(CC) $(CFLAGS) ../OpAny.cpp -c -o $@ - -OpArith.o : ../OpArith.cpp ../app.h - $(CC) $(CFLAGS) ../OpArith.cpp -c -o $@ - -OpBranch.o : ../OpBranch.cpp ../app.h - $(CC) $(CFLAGS) ../OpBranch.cpp -c -o $@ - -OpLogic.o : ../OpLogic.cpp ../app.h - $(CC) $(CFLAGS) ../OpLogic.cpp -c -o $@ - -OpMove.o : ../OpMove.cpp ../app.h - $(CC) $(CFLAGS) ../OpMove.cpp -c -o $@ - -Disa.o : ../Disa/Disa.c ../Disa/Disa.h - $(CC) $(CFLAGS) ../Disa/Disa.c -c -o $@ - -../app.h : ../config.h - -clean : - $(RM) *.o Cyclone.exe Cyclone.s - diff --git a/cpu/Cyclone/proj/Makefile.win b/cpu/Cyclone/proj/Makefile.win deleted file mode 100644 index 758352b..0000000 --- a/cpu/Cyclone/proj/Makefile.win +++ /dev/null @@ -1,59 +0,0 @@ -# Makefile for MS Visual C - -CPP=cl.exe -CPP_PROJ=/nologo /W4 /O2 /D "_CRT_SECURE_NO_WARNINGS" /c - -LINK32=link.exe -LINK32_FLAGS=user32.lib /nologo /subsystem:console /machine:I386 /out:Cyclone.exe - - -ALL : cyclone.s - -cyclone.s : Cyclone.exe - Cyclone.exe - -Cyclone.exe : Main.obj Ea.obj OpAny.obj OpArith.obj OpBranch.obj OpLogic.obj Disa.obj OpMove.obj - $(LINK32) Main.obj Ea.obj OpAny.obj OpArith.obj OpBranch.obj OpLogic.obj Disa.obj OpMove.obj $(LINK32_FLAGS) - -Main.obj : ..\Main.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\Main.cpp - -Ea.obj : ..\Ea.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\Ea.cpp - -OpAny.obj : ..\OpAny.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\OpAny.cpp - -OpArith.obj : ..\OpArith.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\OpArith.cpp - -OpBranch.obj : ..\OpBranch.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\OpBranch.cpp - -OpLogic.obj : ..\OpLogic.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\OpLogic.cpp - -OpMove.obj : ..\OpMove.cpp ..\app.h - $(CPP) $(CPP_PROJ) ..\OpMove.cpp - -Disa.obj : ..\disa\Disa.c ..\disa\Disa.h - $(CPP) $(CPP_PROJ) ..\disa\Disa.c - -..\app.h : ..\config.h - - -CLEAN : - -@erase "Disa.obj" - -@erase "Ea.obj" - -@erase "Main.obj" - -@erase "OpAny.obj" - -@erase "OpArith.obj" - -@erase "OpBranch.obj" - -@erase "OpLogic.obj" - -@erase "OpMove.obj" - -@erase "vc60.idb" - -@erase "vc60.pch" - -@erase "Cyclone.exe" - -@erase "Cyclone.asm" - -@erase "Cyclone.s" - diff --git a/cpu/Cyclone/proj/cyclone.dsp b/cpu/Cyclone/proj/cyclone.dsp deleted file mode 100644 index 1e66725..0000000 --- a/cpu/Cyclone/proj/cyclone.dsp +++ /dev/null @@ -1,146 +0,0 @@ -# Microsoft Developer Studio Project File - Name="cyclone" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=cyclone - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "cyclone.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "cyclone.mak" CFG="cyclone - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "cyclone - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "cyclone - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "cyclone - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W4 /O2 /D "_CRT_SECURE_NO_WARNINGS" /c -# ADD CPP /nologo /W4 /O2 /D "_CRT_SECURE_NO_WARNINGS" /c -# ADD BASE RSC /l 0x427 /d "NDEBUG" -# ADD RSC /l 0x427 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 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 /out:"cyclone.exe" - -!ELSEIF "$(CFG)" == "cyclone - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W4 /O2 /D "_CRT_SECURE_NO_WARNINGS" /c -# ADD CPP /nologo /W4 /O2 /D "_CRT_SECURE_NO_WARNINGS" /c -# ADD BASE RSC /l 0x427 /d "_DEBUG" -# ADD RSC /l 0x427 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 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 /out:"cyclone.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "cyclone - Win32 Release" -# Name "cyclone - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\disa\Disa.c -# End Source File -# Begin Source File - -SOURCE=..\Ea.cpp -# End Source File -# Begin Source File - -SOURCE=..\Main.cpp -# End Source File -# Begin Source File - -SOURCE=..\OpAny.cpp -# End Source File -# Begin Source File - -SOURCE=..\OpArith.cpp -# End Source File -# Begin Source File - -SOURCE=..\OpBranch.cpp -# End Source File -# Begin Source File - -SOURCE=..\OpLogic.cpp -# End Source File -# Begin Source File - -SOURCE=..\OpMove.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=..\app.h -# End Source File -# Begin Source File - -SOURCE=..\config.h -# End Source File -# Begin Source File - -SOURCE=..\Cyclone.h -# End Source File -# Begin Source File - -SOURCE=..\disa\Disa.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/cpu/Cyclone/tests/crash_cyclone.bin b/cpu/Cyclone/tests/crash_cyclone.bin deleted file mode 100755 index dfa0276ad88bc70f5f4a9953056f7eab2435b3d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 524 zcmZQz00AZ@1_qXUKs*7+2JuP2ApQ6NA+zx5rM;ZOpaPwWUTE$Chk*S5{|x_utpET2 g2RUv~U{GLSWKgjGkEWC;ZYY{6zvBP@{R$xv07N`3q5uE@ diff --git a/cpu/Cyclone/tests/test_abcd.bin b/cpu/Cyclone/tests/test_abcd.bin deleted file mode 100755 index fe2504002e8085aa741cf157a6806ab897852f8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 570 zcmZQz00AZ@1_qXUKs*76R{{AzF)$w}hRlYEkxH|AFfhRJBq)0dkPZUc6T`qDZUMwH zKpX@e0P{EdT%e6+$2YZ!K)D diff --git a/cpu/Cyclone/tests/test_cmpm.bin b/cpu/Cyclone/tests/test_cmpm.bin deleted file mode 100755 index e76185787596b4933339a51030d87212fbf10a78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 618 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 diff --git a/cpu/Cyclone/tests/test_misc2_gen.c b/cpu/Cyclone/tests/test_misc2_gen.c deleted file mode 100644 index 108156b..0000000 --- a/cpu/Cyclone/tests/test_misc2_gen.c +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -#include - - -static FILE *f; - -#define bswap16(x) (x=(unsigned short)((x<<8)|(x>>8))) -#define bswap32(x) (x=((x<<24)|((x<<8)&0xff0000)|((x>>8)&0x00ff00)|((unsigned)x>>24))) - -static void write_op(unsigned short op, unsigned short word0, unsigned short word1, unsigned short word2) -{ - bswap16(op); - bswap16(word0); - bswap16(word1); - bswap16(word2); - - fwrite(&op, 1, sizeof(op), f); - fwrite(&word0, 1, sizeof(word0), f); - fwrite(&word1, 1, sizeof(word1), f); - fwrite(&word2, 1, sizeof(word2), f); -} - -static void write32(unsigned int a) -{ - bswap32(a); - fwrite(&a, 1, sizeof(a), f); -} - -static int op_check(unsigned short op) -{ - if ((op&0xf000) == 0x6000) return 0; // Bxx - if ((op&0xf0f8) == 0x50c8) return 0; // DBxx - if ((op&0xff80) == 0x4e80) return 0; // Jsr - if ((op&0xf000) == 0xa000) return 0; // a-line - if ((op&0xf000) == 0xf000) return 0; // f-line - if ((op&0xfff8)==0x4e70&&op!=0x4e71&&op!=0x4e76) return 0; // reset, rte, rts - - if ((op&0x3f) >= 0x28) op = (op&~0x3f) | (rand() % 0x28); - return 1; -} - -static unsigned short safe_rand(void) -{ - unsigned short op; - - /* avoid branch opcodes */ - do - { - op = rand(); - } - while (!op_check(op)); - - return op; -} - -int main() -{ - int i, op; - - srand(time(0)); - - f = fopen("test_misc2.bin", "wb"); - if (!f) return 1; - - write32(0x00ff8000); // stack - write32(0x300); // IP - - for (i=0x100/4-2; i; i--) - { - write32(0x200+i*4); // exception vectors - } - - for (i=0x100/4; i; i--) - { - write32(0); // pad - } - - for (i=0x100/4; i; i--) - { - write32(0x4e734e73); // fill with rte instructions - } - - for (op = 0; op < 0x10000; op++) - { - if ((op&0xf000) == 0x6000) // Bxx - { - if ((op&0x00ff) == 0) - write_op(op, 6, 0, 0); - } - else if ((op&0xf0f8)==0x50c8) // DBxx - { - write_op(op, 6, 0, 0); - } - else if ((op&0xff80)==0x4e80) // Jsr - { - int addr = 0x300 + op*8 + 8; - if ((op&0x3f) == 0x39) - write_op(op, addr >> 16, addr & 0xffff, 0); - } - else if ((op&0xf000)==0xa000 || (op&0xf000)==0xf000) // a-line, f-line - { - if (op != 0xa000 && op != 0xf000) continue; - } - else if ((op&0xfff8)==0x4e70&&op!=0x4e71&&op!=0x4e76); // rte, rts, stop, reset - else - { - write_op(op, safe_rand(), safe_rand(), safe_rand()); - } - } - - // jump to the beginning - write_op(0x4ef8, 0x300, 0x4ef8, 0x300); - write_op(0x4ef8, 0x300, 0x4ef8, 0x300); - - fclose(f); - return 0; -} - diff --git a/cpu/Cyclone/tests/test_negx.bin b/cpu/Cyclone/tests/test_negx.bin deleted file mode 100755 index 1f6e6cf696d2ce5adc111b6feffc80d209f7542b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 542 zcmZQz00AZ-X1NE%6M%RX5Fdf^L1I+EtR4&ua6Adho&uzUfab?AFo;_Ku?!H005Q-l ztYJW01yu*s%YF{QhMNO5lQQ=OySh6nxV!qf273l80D*?HCRoVO($YlFE7ZrOG`Ao% zMZu|3AtcxZq<{bj_VD!c^mA8m^AB=%RWKr;T0z0xSHag?*U;F|R6*Ckpi|KcO$R7; z807!|XZR1K|Ns9V;p=hcK{uli(VN|nWU}#`)XmDtBU~+K& J|KG0=0s)GBWj+7^ diff --git a/cpu/Cyclone/tests/test_rol.bin b/cpu/Cyclone/tests/test_rol.bin deleted file mode 100755 index 0cb0a412cd64c087b84bcb2d16456525618108cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 578 zcmZQz00AZ@1_qXUKs*76R{{AzF)$w}hRlYEkxH|AFfhRJBq)0dkPZUc6T`qDZUMwH zKpX34rV0>iZ ra2(3!e_Y{k49aGBRN-*6fLX}~Xn*759S%ndn2Q)5@A&`UuMh$OHxz9b diff --git a/cpu/Cyclone/tests/test_shift.bin b/cpu/Cyclone/tests/test_shift.bin deleted file mode 100755 index c364f218c817a76856e3d9afb111e5cf041558fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 582 zcmZQz00AZ@1_qXUKs*76R{{AzF)$w}hRlYEkxH|AFfhRJBq)0dkPZUc6T`qDZUMwH zKpX34rV0@(D va2(2JaQmbF|M3ckV^BW-;{=DJ3N}C&G!!ub)g38dE|Pz|;{SiYLI?x^3es-$ diff --git a/cpu/Cyclone/tests/test_trace.bin b/cpu/Cyclone/tests/test_trace.bin deleted file mode 100755 index e9ca5fa9d3c0b901da110c53bda826347b9c8d4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 558 zcmZQzU|?uqU}9rnV7Ujx6M%RX5Fdf^L1OoS@<3H!c`%=JHme5%0~}9+vZny)AfQ<> z3=HBHKr92qAwUeYi!}_0tDx$DdfCq**l=^8W>VrVmV3dj?v4uXu70k;p1}%0py8|u z7BaN7G|}@4^>Hc9El5pKaH>=Y33dS~AOM0rJpDZV+!fsXgPdIzj0mV!P;mEE@b%U; zG&VF<&^0jVRP;jA0SpWV2KoR08U6$5|Ns97Ic`v3P+(wWP_X}xrj#gdD4Ht2LLe+I n_+Rwj?ay+-5=J!}P" "<0><1><0>" ?"<0xFF> | Modem_Infos - .ascii " " - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | -aU: .ascii "U " | Countries - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | - .byte 0x20 | -_trace: - nop - nop - rte - -.globl _start -_start: - move.l #0xFFFFFFFF, %d0 - move.l #0xFFFFFFFF, %d1 - move.w #0xa711, %sr - move.l #0x1, %d2 - move.l #0x8000, %d3 - negx.l %d0 - negx.l %d1 - move.w #0x270f, %sr - negx.b %d2 - negx.w %d3 -_loop: - bra _loop - - nop - nop - nop - nop diff --git a/cpu/Cyclone/tools/idle.h b/cpu/Cyclone/tools/idle.h deleted file mode 100644 index 254cc57..0000000 --- a/cpu/Cyclone/tools/idle.h +++ /dev/null @@ -1,3 +0,0 @@ - -void CycloneInitIdle(void); -void CycloneFinishIdle(void); diff --git a/cpu/Cyclone/tools/idle.s b/cpu/Cyclone/tools/idle.s deleted file mode 100644 index a8b7cca..0000000 --- a/cpu/Cyclone/tools/idle.s +++ /dev/null @@ -1,176 +0,0 @@ -@ vim:filetype=armasm - -@ ranges/opcodes (idle, normal): -@ 71xx, 73xx - bne.s (8bit offset) -@ 75xx, 77xx - beq.s (8bit offset) -@ 7dxx, 7fxx - bra.s (8bit offset) - -.data -.align 2 - -have_patches: - .word 0 - -.equ patch_desc_table_size, 10 - -patch_desc_table: - .word (0x71fa<<16) | 0x66fa, idle_detector_bcc8, idle_bne, Op6601 @ bne.s - .word (0x71f8<<16) | 0x66f8, idle_detector_bcc8, idle_bne, Op6601 @ bne.s - .word (0x71f6<<16) | 0x66f6, idle_detector_bcc8, idle_bne, Op6601 @ bne.s - .word (0x71f2<<16) | 0x66f2, idle_detector_bcc8, idle_bne, Op6601 @ bne.s - .word (0x75fa<<16) | 0x67fa, idle_detector_bcc8, idle_beq, Op6701 @ beq.s - .word (0x75f8<<16) | 0x67f8, idle_detector_bcc8, idle_beq, Op6701 @ beq.s - .word (0x75f6<<16) | 0x67f6, idle_detector_bcc8, idle_beq, Op6701 @ beq.s - .word (0x75f2<<16) | 0x67f2, idle_detector_bcc8, idle_beq, Op6701 @ beq.s - .word (0x7dfe<<16) | 0x60fe, idle_detector_bcc8, idle_bra, Op6001 @ bra.s - .word (0x7dfc<<16) | 0x60fc, idle_detector_bcc8, idle_bra, Op6001 @ bra.s - - -.text -.align 2 - - -.global CycloneInitIdle - -CycloneInitIdle: - ldr r3, =CycloneJumpTab - ldr r2, =patch_desc_table - mov r12,#patch_desc_table_size - -cii_loop: - ldrh r0, [r2] - ldr r1, [r2, #4] @ detector - str r1, [r3, r0, lsl #2] - ldrh r0, [r2, #2] - ldr r1, [r2, #8] @ idle - add r0, r3, r0, lsl #2 - str r1, [r0] - ldr r1, [r2, #12] @ normal - str r1, [r0, #0x800] - add r2, r2, #16 - subs r12,r12,#1 - bgt cii_loop - - ldr r0, =have_patches - mov r1, #1 - str r1, [r0] - bx lr - - -.global CycloneFinishIdle - -CycloneFinishIdle: - ldr r0, =have_patches - ldr r0, [r0] - tst r0, r0 - bxeq lr - - ldr r3, =CycloneJumpTab - ldr r2, =patch_desc_table - mov r12,#patch_desc_table_size - -cfi_loop: - ldrh r0, [r2] - ldr r1, [r2, #12] @ normal - str r1, [r3, r0, lsl #2] - ldrh r0, [r2, #2] - ldr r1, =Op____ - add r0, r3, r0, lsl #2 - str r1, [r0] - str r1, [r0, #0x800] - add r2, r2, #16 - subs r12,r12,#1 - bgt cfi_loop - - ldr r0, =have_patches - mov r1, #0 - str r1, [r0] - bx lr - - - -.macro inc_counter cond -@ ldr\cond r0, [r7, #0x60] -@ mov r11,lr -@ sub r0, r4, r0 -@ sub r0, r0, #2 -@ bl\cond SekRegisterIdleHit -@ mov lr, r11 -.endm - -idle_bra: - mov r5, #2 - inc_counter - b Op6001 - -idle_bne: - msr cpsr_flg, r10 - movne r5, #2 @ 2 is intentional due to strange timing issues - inc_counter ne - b Op6601 - -idle_beq: - msr cpsr_flg, r10 ;@ ARM flags = 68000 flags - moveq r5, #2 - inc_counter eq - b Op6701 - - -@ @@@ @ - -idle_detector_bcc8: - ldr r0, =(Pico+0x22208) @ Pico.m - ldr r1, =idledet_start_frame - ldr r0, [r0, #0x1c] @ ..frame_count - ldr r1, [r1] - cmp r0, r1 - blt exit_detector @ not yet - - mov r0, r8, asl #24 @ Shift 8-bit signed offset up... - add r0, r4, r0, asr #24 @ jump dest - bic r0, r0, #1 - - mov r1, #0 - sub r1, r1, r8, lsl #24 - mov r1, r1, lsr #24 - sub r1, r1, #2 - bic r1, r1, #1 - - bl SekIsIdleCode - tst r0, r0 - and r2, r8, #0x00ff - orr r2, r2, #0x7100 - orreq r2, r2, #0x0200 - mov r0, r8, lsr #8 - cmp r0, #0x66 - orrgt r2, r2, #0x0400 @ 67xx (beq) - orrlt r2, r2, #0x0c00 @ 60xx (bra) - - @ r2 = patch_opcode - sub r0, r4, #2 - ldrh r1, [r0] - mov r11,r2 - mov r3, r7 - bl SekRegisterIdlePatch - cmp r0, #1 @ 0 - ok to patch, 1 - no patch, 2 - remove detector - strlth r11,[r4, #-2] - ble exit_detector - - @ remove detector from Cyclone - mov r0, r8, lsr #8 - cmp r0, #0x66 - ldrlt r1, =Op6001 - ldreq r1, =Op6601 - ldrgt r1, =Op6701 - - ldr r3, =CycloneJumpTab - str r1, [r3, r8, lsl #2] - bx r1 - -exit_detector: - mov r0, r8, lsr #8 - cmp r0, #0x66 - blt Op6001 - beq Op6601 - b Op6701 - diff --git a/cpu/cyclone b/cpu/cyclone new file mode 160000 index 0000000..a6905b4 --- /dev/null +++ b/cpu/cyclone @@ -0,0 +1 @@ +Subproject commit a6905b4de17f4d772c7742065f2863b77ddf0b31 diff --git a/cpu/Cyclone/config_pico.h b/cpu/cyclone_config.h similarity index 100% rename from cpu/Cyclone/config_pico.h rename to cpu/cyclone_config.h -- 2.39.2