| 1 | \r |
| 2 | _____ __ \r |
| 3 | / ___/__ __ ____ / /___ ___ ___ ___________________ \r |
| 4 | / /__ / // // __// // _ \ / _ \/ -_) ___________________ \r |
| 5 | \___/ \_, / \__//_/ \___//_//_/\__/ ___________________ \r |
| 6 | /___/ \r |
| 7 | ___________________ ____ ___ ___ ___ ___ \r |
| 8 | ___________________ / __// _ \ / _ \ / _ \ / _ \ \r |
| 9 | ___________________ / _ \/ _ // // // // // // / \r |
| 10 | \___/\___/ \___/ \___/ \___/ \r |
| 11 | \r |
| 12 | ___________________________________________________________________________\r |
| 13 | \r |
| 14 | Cyclone 68000 (c) Copyright 2004 Dave. Free for non-commercial use\r |
| 15 | \r |
| 16 | Homepage: http://www.finalburn.com/\r |
| 17 | Dave's e-mail: emudave(atsymbol)googlemail.com\r |
| 18 | Replace (atsymbol) with @\r |
| 19 | \r |
| 20 | Additional coding and bugfixes done by notaz, 2005-2007\r |
| 21 | Homepage: http://notaz.gp2x.de\r |
| 22 | e-mail: notasas(atsymbol)gmail.com\r |
| 23 | ___________________________________________________________________________\r |
| 24 | \r |
| 25 | \r |
| 26 | About\r |
| 27 | -----\r |
| 28 | \r |
| 29 | Cyclone 68000 is an emulator for the 68000 microprocessor, written in ARM 32-bit assembly.\r |
| 30 | It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret 68000\r |
| 31 | code as fast as possible. It can emulate all 68000 instructions quite accurately, instruction\r |
| 32 | timing was synchronized with MAME's Musashi. Most 68k features are emulated (trace mode,\r |
| 33 | address errors), but prefetch is not emulated.\r |
| 34 | \r |
| 35 | \r |
| 36 | How to Compile\r |
| 37 | --------------\r |
| 38 | \r |
| 39 | Like Starscream and A68K, Cyclone uses a 'Core Creator' program which calculates and outputs\r |
| 40 | all possible 68000 Opcodes and a jump table into file called Cyclone.s or Cyclone.asm.\r |
| 41 | Only Cyclone.h and the mentioned .s or .asm file will be needed for your project, other files\r |
| 42 | are here to produce or test it.\r |
| 43 | \r |
| 44 | First unzip "Cyclone.zip" into a "Cyclone" directory. The next thing to do is to edit config.h\r |
| 45 | file to tune Cyclone for your project. There are lots of options in config.h, but all of them\r |
| 46 | are documented and have defaults. You should set a define value to 1 to enable option, and\r |
| 47 | to 0 to disable.\r |
| 48 | \r |
| 49 | After you are done with config.h, save it and compile Cyclone. If you are using Linux, Cygwin,\r |
| 50 | mingw or similar, you can simply cd to Cyclone/proj and type "make". If you are under Windows\r |
| 51 | and have Visual Studio installed, you can import cyclone.dsp in the proj/ directory and compile\r |
| 52 | it from there (this will produce cyclone.exe which you will have to run to get .s or .asm).\r |
| 53 | You can also use Microsoft command line compile tools by entering Cyclone/proj directory and\r |
| 54 | typing "nmake -f Makefile.win". Note that this step is done only to produce .s or .asm, and it\r |
| 55 | is done using native tools on your PC (not using cross-compiler or similar).\r |
| 56 | \r |
| 57 | The .s file is meant to be compiled with GNU assembler, and .asm with ARMASM.EXE\r |
| 58 | (the Microsoft ARM assembler). Once you have the file, you can add it to your\r |
| 59 | Makefile/project/whatever.\r |
| 60 | \r |
| 61 | \r |
| 62 | Adding to your project\r |
| 63 | ----------------------\r |
| 64 | \r |
| 65 | Compiling the .s or .asm (from previous step) for your target platform may require custom\r |
| 66 | build rules in your Makefile/project.\r |
| 67 | \r |
| 68 | If you use some gcc-based toolchain, you will need to add Cyclone.o to an object list in\r |
| 69 | the Makefile. GNU make will use "as" to build Cyclone.o from Cyclone.s by default, so\r |
| 70 | you may need to define correct cross-assembler by setting AS variable like this:\r |
| 71 | \r |
| 72 | AS = arm-linux-as\r |
| 73 | \r |
| 74 | This might be different in your case, basically it should be same prefix as for gcc.\r |
| 75 | You may also need to specify floating point type in your assembler flags for Cyclone.o\r |
| 76 | to link properly. This is done like this:\r |
| 77 | \r |
| 78 | ASFLAGS = -mfloat-abi=soft\r |
| 79 | \r |
| 80 | Note that Cyclone does not use floating points, this is just to make the linker happy.\r |
| 81 | \r |
| 82 | \r |
| 83 | If you are using Visual Studio, you may need to add "custom build step", which creates\r |
| 84 | Cyclone.obj from Cyclone.asm (asmasm.exe Cyclone.asm). Alternatively you can create\r |
| 85 | Cyclone.obj by using armasm once and then just add it to you project.\r |
| 86 | \r |
| 87 | Don't worry if this seem very minimal - its all you need to run as many 68000s as you want.\r |
| 88 | It works with both C and C++.\r |
| 89 | \r |
| 90 | \r |
| 91 | Byteswapped Memory\r |
| 92 | ------------------\r |
| 93 | \r |
| 94 | If you have used Starscream, A68K or Turbo68K or similar emulators you'll be familiar with this!\r |
| 95 | \r |
| 96 | Any memory which the 68000 can access directly must be have every two bytes swapped around.\r |
| 97 | This is to speed up 16-bit memory accesses, because the 68000 has Big-Endian memory\r |
| 98 | and ARM has Little-Endian memory (in most cases).\r |
| 99 | \r |
| 100 | Now you may think you only technically have to byteswap ROM, not RAM, because\r |
| 101 | 16-bit RAM reads go through a memory handler and you could just return (mem[a]<<8) | mem[a+1].\r |
| 102 | \r |
| 103 | This would work, but remember some systems can execute code from RAM as well as ROM, and\r |
| 104 | that would fail.\r |
| 105 | So it's best to use byteswapped ROM and RAM if the 68000 can access it directly.\r |
| 106 | It's also faster for the memory handlers, because you can do this:\r |
| 107 | \r |
| 108 | return *(unsigned short *)(mem+a)\r |
| 109 | \r |
| 110 | \r |
| 111 | Declaring Memory handlers\r |
| 112 | -------------------------\r |
| 113 | \r |
| 114 | Before you can reset or execute 68000 opcodes you must first set up a set of memory handlers.\r |
| 115 | There are 7 functions you have to set up per CPU, like this:\r |
| 116 | \r |
| 117 | static unsigned int MyCheckPc(unsigned int pc)\r |
| 118 | static unsigned char MyRead8 (unsigned int a)\r |
| 119 | static unsigned short MyRead16 (unsigned int a)\r |
| 120 | static unsigned int MyRead32 (unsigned int a)\r |
| 121 | static void MyWrite8 (unsigned int a,unsigned char d)\r |
| 122 | static void MyWrite16(unsigned int a,unsigned short d)\r |
| 123 | static void MyWrite32(unsigned int a,unsigned int d)\r |
| 124 | \r |
| 125 | You can think of these functions representing the 68000's memory bus.\r |
| 126 | The Read and Write functions are called whenever the 68000 reads or writes memory.\r |
| 127 | For example you might set MyRead8 like this:\r |
| 128 | \r |
| 129 | unsigned char MyRead8(unsigned int a)\r |
| 130 | {\r |
| 131 | a&=0xffffff; // Clip address to 24-bits\r |
| 132 | \r |
| 133 | if (a<RomLength) return RomData[a^1]; // ^1 because the memory is byteswapped\r |
| 134 | if (a>=0xe00000) return RamData[(a^1)&0xffff];\r |
| 135 | return 0xff; // Out of range memory access\r |
| 136 | }\r |
| 137 | \r |
| 138 | The other 5 read/write functions are similar. I'll describe the CheckPc function later on.\r |
| 139 | \r |
| 140 | \r |
| 141 | Declaring a CPU Context\r |
| 142 | -----------------------\r |
| 143 | \r |
| 144 | To declare a CPU simple declare a struct Cyclone in your code (don't forget to include Cyclone.h).\r |
| 145 | For example to declare two 68000s:\r |
| 146 | \r |
| 147 | struct Cyclone MyCpu;\r |
| 148 | struct Cyclone MyCpu2;\r |
| 149 | \r |
| 150 | It's probably a good idea to initialize the memory to zero:\r |
| 151 | \r |
| 152 | memset(&MyCpu, 0,sizeof(MyCpu));\r |
| 153 | memset(&MyCpu2,0,sizeof(MyCpu2));\r |
| 154 | \r |
| 155 | Next point to your memory handlers:\r |
| 156 | \r |
| 157 | MyCpu.checkpc=MyCheckPc;\r |
| 158 | MyCpu.read8 =MyRead8;\r |
| 159 | MyCpu.read16 =MyRead16;\r |
| 160 | MyCpu.read32 =MyRead32;\r |
| 161 | MyCpu.write8 =MyWrite8;\r |
| 162 | MyCpu.write16=MyWrite16;\r |
| 163 | MyCpu.write32=MyWrite32;\r |
| 164 | \r |
| 165 | You also need to point the fetch handlers - for most systems out there you can just\r |
| 166 | point them at the read handlers:\r |
| 167 | MyCpu.fetch8 =MyRead8;\r |
| 168 | MyCpu.fetch16 =MyRead16;\r |
| 169 | MyCpu.fetch32 =MyRead32;\r |
| 170 | \r |
| 171 | ( Why a different set of function pointers for fetch?\r |
| 172 | Well there are some systems, the main one being CPS2, which return different data\r |
| 173 | depending on whether the 'fetch' line on the 68000 bus is high or low.\r |
| 174 | If this is the case, you can set up different functions for fetch reads.\r |
| 175 | Generally though you don't need to. )\r |
| 176 | \r |
| 177 | Now you are nearly ready to reset the 68000, except a few more functions,\r |
| 178 | one of them is: checkpc().\r |
| 179 | \r |
| 180 | \r |
| 181 | The checkpc() function\r |
| 182 | ----------------------\r |
| 183 | \r |
| 184 | When Cyclone reads opcodes, it doesn't use a memory handler every time, this would be\r |
| 185 | far too slow, instead it uses a direct pointer to ARM memory.\r |
| 186 | For example if your Rom image was at 0x3000000 and the program counter was $206,\r |
| 187 | Cyclone's program counter would be 0x3000206.\r |
| 188 | \r |
| 189 | The difference between an ARM address and a 68000 address is also stored in a variable called\r |
| 190 | 'membase'. In the above example it's 0x3000000. To retrieve the real 68k PC, Cyclone just\r |
| 191 | subtracts 'membase'.\r |
| 192 | \r |
| 193 | When a long jump happens, Cyclone calls checkpc(). If the PC is in a different bank,\r |
| 194 | for example Ram instead of Rom, change 'membase', recalculate the new PC and return it:\r |
| 195 | \r |
| 196 | static int MyCheckPc(unsigned int pc)\r |
| 197 | {\r |
| 198 | pc-=MyCpu.membase; // Get the real program counter\r |
| 199 | \r |
| 200 | if (pc<RomLength) MyCpu.membase=(int)RomMem; // Jump to Rom\r |
| 201 | if (pc>=0xff0000) MyCpu.membase=(int)RamMem-0xff0000; // Jump to Ram\r |
| 202 | \r |
| 203 | return MyCpu.membase+pc; // New program counter\r |
| 204 | }\r |
| 205 | \r |
| 206 | Notice that the membase is always ARM address minus 68000 address.\r |
| 207 | \r |
| 208 | The above example doesn't consider mirrored ram, but for an example of what to do see\r |
| 209 | PicoDrive (in Memory.c).\r |
| 210 | \r |
| 211 | The exact cases when checkpc() is called can be configured in config.h.\r |
| 212 | \r |
| 213 | \r |
| 214 | Initialization\r |
| 215 | --------------\r |
| 216 | \r |
| 217 | Add a call to CycloneInit(). This is really only needed to be called once at startup\r |
| 218 | if you enabled COMPRESS_JUMPTABLE in config.h, but you can add this in any case,\r |
| 219 | it won't hurt.\r |
| 220 | \r |
| 221 | \r |
| 222 | Almost there - Reset the 68000!\r |
| 223 | -------------------------------\r |
| 224 | \r |
| 225 | Cyclone doesn't provide a reset function, so next we need to Reset the 68000 to get\r |
| 226 | the initial Program Counter and Stack Pointer. This is obtained from addresses\r |
| 227 | 000000 and 000004.\r |
| 228 | \r |
| 229 | Here is code which resets the 68000 (using your memory handlers):\r |
| 230 | \r |
| 231 | MyCpu.state_flags=0; // Go to default state (not stopped, halted, etc.)\r |
| 232 | MyCpu.srh=0x27; // Set supervisor mode\r |
| 233 | MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer\r |
| 234 | MyCpu.membase=0; // Will be set by checkpc()\r |
| 235 | MyCpu.pc=MyCpu.checkpc(MyCpu.read32(4)); // Get Program Counter\r |
| 236 | \r |
| 237 | And that's ready to go.\r |
| 238 | \r |
| 239 | \r |
| 240 | Executing the 68000\r |
| 241 | -------------------\r |
| 242 | \r |
| 243 | To execute the 68000, set the 'cycles' variable to the number of cycles you wish to execute,\r |
| 244 | and then call CycloneRun with a pointer to the Cyclone structure.\r |
| 245 | \r |
| 246 | e.g.:\r |
| 247 | // Execute 1000 cycles on the 68000:\r |
| 248 | MyCpu.cycles=1000; CycloneRun(&MyCpu);\r |
| 249 | \r |
| 250 | For each opcode, the number of cycles it took is subtracted and the function returns when\r |
| 251 | it reaches negative number. The result is stored back to MyCpu.cycles.\r |
| 252 | \r |
| 253 | e.g.\r |
| 254 | // Execute one instruction on the 68000:\r |
| 255 | MyCpu.cycles=0; CycloneRun(&MyCpu);\r |
| 256 | printf(" The opcode took %d cycles\n", -MyCpu.cycles);\r |
| 257 | \r |
| 258 | You should try to execute as many cycles as you can for maximum speed.\r |
| 259 | The number actually executed may be slightly more than requested, i.e. cycles may come\r |
| 260 | out with a small negative value:\r |
| 261 | \r |
| 262 | e.g.\r |
| 263 | int todo=12000000/60; // 12Mhz, for one 60hz frame\r |
| 264 | MyCpu.cycles=todo; CycloneRun(&MyCpu);\r |
| 265 | printf(" Actually executed %d cycles\n", todo-MyCpu.cycles);\r |
| 266 | \r |
| 267 | To calculate the number of cycles executed, use this formula:\r |
| 268 | Number of cycles requested - Cycle counter at the end\r |
| 269 | \r |
| 270 | \r |
| 271 | Interrupts\r |
| 272 | ----------\r |
| 273 | \r |
| 274 | Causing an interrupt is very simple, simply set the irq variable in the Cyclone structure\r |
| 275 | to the IRQ number.\r |
| 276 | To lower the IRQ line, set it to zero.\r |
| 277 | \r |
| 278 | e.g:\r |
| 279 | MyCpu.irq=6; // Interrupt level 6\r |
| 280 | MyCpu.cycles=20000; CycloneRun(&MyCpu);\r |
| 281 | \r |
| 282 | Note that the interrupt is not actually processed until the next call to CycloneRun,\r |
| 283 | and the interrupt may not be taken until the 68000 interrupt mask is changed to allow it.\r |
| 284 | \r |
| 285 | If you need to force interrupt processing, you can use CycloneFlushIrq() function.\r |
| 286 | It is the same as doing\r |
| 287 | \r |
| 288 | MyCpu.cycles=0; CycloneRun(&MyCpu);\r |
| 289 | \r |
| 290 | but is better optimized and doesn't update .cycles (returns them instead).\r |
| 291 | This function can't be used from memory handlers and has no effect if interrupt is masked.\r |
| 292 | \r |
| 293 | The IRQ isn't checked on exiting from a memory handler. If you need to cause interrupt\r |
| 294 | check immediately, you should change cycle counter to 0 to cause a return from CycloneRun(),\r |
| 295 | and then call CycloneRun() again or just call CycloneFlushIrq(). Note that you need to\r |
| 296 | enable MEMHANDLERS_CHANGE_CYCLES in config.h for this to work.\r |
| 297 | \r |
| 298 | If you need to do something during the interrupt acknowledge (the moment when interrupt\r |
| 299 | is taken), you can set USE_INT_ACK_CALLBACK in config.h and specify IrqCallback function.\r |
| 300 | This function should update the IRQ level (.irq variable in context) and return the\r |
| 301 | interrupt vector number. But for most cases it should return special constant\r |
| 302 | CYCLONE_INT_ACK_AUTOVECTOR so that Cyclone uses autovectors, which is what most real\r |
| 303 | systems were doing. Another less commonly used option is to return CYCLONE_INT_ACK_SPURIOUS\r |
| 304 | for spurious interrupt.\r |
| 305 | \r |
| 306 | \r |
| 307 | Accessing Program Counter and registers\r |
| 308 | ---------------------------------------\r |
| 309 | \r |
| 310 | You can read most Cyclone's registers directly from the structure at any time.\r |
| 311 | However, the PC value, CCR and cycle counter are cached in ARM registers and can't\r |
| 312 | be accessed from memory handlers by default. They are written back and can be\r |
| 313 | accessed after execution.\r |
| 314 | \r |
| 315 | But if you need to access the mentioned registers during execution, you can set\r |
| 316 | MEMHANDLERS_NEED_* and MEMHANDLERS_CHANGE_* options in config.h\r |
| 317 | \r |
| 318 | The Program Counter, should you need to read or write it, is stored with membase\r |
| 319 | added on. So use this formula to calculate the real 68000 program counter:\r |
| 320 | \r |
| 321 | pc = MyCpu.pc - MyCpu.membase;\r |
| 322 | \r |
| 323 | For performance reasons Cyclone keeps the status register split into .srh\r |
| 324 | (status register "high" supervisor byte), .xc for the X flag, and .flags for remaining\r |
| 325 | CCR flags (in ARM order). To easily read/write the status register as normal 68k\r |
| 326 | 16bit SR register, use CycloneGetSr() and CycloneSetSr() utility functions.\r |
| 327 | \r |
| 328 | \r |
| 329 | Emulating more than one CPU\r |
| 330 | ---------------------------\r |
| 331 | \r |
| 332 | Since everything is based on the structures, emulating more than one cpu at the same time\r |
| 333 | is just a matter of declaring more than one structures and timeslicing. You can emulate\r |
| 334 | as many 68000s as you want.\r |
| 335 | Just set up the memory handlers for each cpu and run each cpu for a certain number of cycles.\r |
| 336 | \r |
| 337 | e.g.\r |
| 338 | // Execute 1000 cycles on 68000 #1:\r |
| 339 | MyCpu.cycles=1000; CycloneRun(&MyCpu);\r |
| 340 | \r |
| 341 | // Execute 1000 cycles on 68000 #2:\r |
| 342 | MyCpu2.cycles=1000; CycloneRun(&MyCpu2);\r |
| 343 | \r |
| 344 | \r |
| 345 | Quick API reference\r |
| 346 | -------------------\r |
| 347 | \r |
| 348 | void CycloneInit(void);\r |
| 349 | Initializes Cyclone. Must be called if the jumptable is compressed,\r |
| 350 | doesn't matter otherwise.\r |
| 351 | \r |
| 352 | void CycloneRun(struct Cyclone *pcy);\r |
| 353 | Runs cyclone for pcy->cycles. Writes amount of cycles left back to\r |
| 354 | pcy->cycles (always negative).\r |
| 355 | \r |
| 356 | unsigned int CycloneGetSr(const struct Cyclone *pcy);\r |
| 357 | Reads status register in internal form from pcy, converts to standard 68k SR and returns it.\r |
| 358 | \r |
| 359 | void CycloneSetSr(struct Cyclone *pcy, unsigned int sr);\r |
| 360 | Takes standard 68k status register (sr), and updates Cyclone context with it.\r |
| 361 | \r |
| 362 | int CycloneFlushIrq(struct Cyclone *pcy);\r |
| 363 | If .irq is greater than IRQ mask in SR, or it is equal to 7 (NMI), processes interrupt\r |
| 364 | exception and returns number of cycles used. Otherwise, does nothing and returns 0.\r |
| 365 | \r |
| 366 | void CyclonePack(const struct Cyclone *pcy, void *save_buffer);\r |
| 367 | Writes Cyclone state to save_buffer. This allows to avoid all the trouble figuring what\r |
| 368 | actually needs to be saved from the Cyclone structure, as saving whole struct Cyclone\r |
| 369 | to a file will also save various pointers, which may become invalid after your program\r |
| 370 | is restarted, so simply reloading the structure will cause a crash. save_buffer size\r |
| 371 | should be 128 bytes (now it is really using less, but this allows future expansion).\r |
| 372 | \r |
| 373 | void CycloneUnpack(struct Cyclone *pcy, const void *save_buffer);\r |
| 374 | Reloads Cyclone state from save_buffer, which was previously saved by CyclonePack().\r |
| 375 | This function uses checkpc() callback to rebase the PC, so .checkpc must be initialized\r |
| 376 | before calling it.\r |
| 377 | \r |
| 378 | Callbacks:\r |
| 379 | \r |
| 380 | .checkpc\r |
| 381 | unsigned int (*checkpc)(unsigned int pc);\r |
| 382 | This function is called when PC changes are performed in 68k code or because of exceptions.\r |
| 383 | It is passed ARM pointer and should return ARM pointer casted to int. It must also update\r |
| 384 | .membase if needed. See "The checkpc() function" section above.\r |
| 385 | \r |
| 386 | unsigned int (*read8 )(unsigned int a);\r |
| 387 | unsigned int (*read16 )(unsigned int a);\r |
| 388 | unsigned int (*read32 )(unsigned int a);\r |
| 389 | These are the read memory handler callbacks. They are called when 68k code reads from memory.\r |
| 390 | The parameter is a 68k address in data space, return value is a data value read. Data value\r |
| 391 | doesn't have to be masked to 8 or 16 bits for read8 or read16, Cyclone will do that itself\r |
| 392 | if needed.\r |
| 393 | \r |
| 394 | unsigned int (*fetch8 )(unsigned int a);\r |
| 395 | unsigned int (*fetch16)(unsigned int a);\r |
| 396 | unsigned int (*fetch32)(unsigned int a);\r |
| 397 | Same as above, but these are reads from program space (PC relative reads mostly).\r |
| 398 | \r |
| 399 | void (*write8 )(unsigned int a,unsigned char d);\r |
| 400 | void (*write16)(unsigned int a,unsigned short d);\r |
| 401 | void (*write32)(unsigned int a,unsigned int d);\r |
| 402 | These are called when 68k code writes to data space. d is the data value.\r |
| 403 | \r |
| 404 | int (*IrqCallback)(int int_level);\r |
| 405 | This function is called when Cyclone acknowledges an interrupt. The parameter is the IRQ\r |
| 406 | level being acknowledged, and return value is exception vector to use, or one of these special\r |
| 407 | values: CYCLONE_INT_ACK_AUTOVECTOR or CYCLONE_INT_ACK_SPURIOUS. Can be disabled in config.h.\r |
| 408 | See "Interrupts" section for more information.\r |
| 409 | \r |
| 410 | void (*ResetCallback)(void);\r |
| 411 | Cyclone will call this function if it encounters RESET 68k instruction.\r |
| 412 | Can be disabled in config.h.\r |
| 413 | \r |
| 414 | int (*UnrecognizedCallback)(void);\r |
| 415 | Cyclone will call this function if it encounters illegal instructions (including A-line and\r |
| 416 | F-line ones). Can be tuned / disabled in config.h.\r |
| 417 | \r |
| 418 | \r |
| 419 | Function codes\r |
| 420 | --------------\r |
| 421 | \r |
| 422 | Cyclone doesn't pass function codes to it's memory handlers, but they can be calculated:\r |
| 423 | FC2: just use supervisor state bit from status register (eg. (MyCpu.srh & 0x20) >> 5)\r |
| 424 | FC1: if we are in fetch* function, then 1, else 0.\r |
| 425 | FC0: if we are in read* or write*, then 1, else 0.\r |
| 426 | CPU state (all FC bits set) is active in IrqCallback function.\r |
| 427 | \r |
| 428 | \r |
| 429 | References\r |
| 430 | ----------\r |
| 431 | \r |
| 432 | These documents were used while writing Cyclone and should be useful for those who want to\r |
| 433 | understand deeper how the 68000 works.\r |
| 434 | \r |
| 435 | MOTOROLA M68000 FAMILY Programmer's Reference Manual\r |
| 436 | common name: 68kPM.pdf\r |
| 437 | \r |
| 438 | M68000 8-/16-/32-Bit Microprocessors User's Manual\r |
| 439 | common name: MC68000UM.pdf\r |
| 440 | \r |
| 441 | 68000 Undocumented Behavior Notes by Bart Trzynadlowski\r |
| 442 | http://www.trzy.org/files/68knotes.txt\r |
| 443 | \r |
| 444 | Instruction prefetch on the Motorola 68000 processor by Jorge Cwik\r |
| 445 | http://pasti.fxatari.com/68kdocs/68kPrefetch.html\r |
| 446 | \r |
| 447 | \r |
| 448 | ARM Register Usage\r |
| 449 | ------------------\r |
| 450 | \r |
| 451 | See source code for up to date of register usage, however a summary is here:\r |
| 452 | \r |
| 453 | r0-3: Temporary registers\r |
| 454 | r4 : Current PC + Memory Base (i.e. pointer to next opcode)\r |
| 455 | r5 : Cycles remaining\r |
| 456 | r6 : Pointer to Opcode Jump table\r |
| 457 | r7 : Pointer to Cpu Context\r |
| 458 | r8 : Current Opcode\r |
| 459 | r10 : Flags (NZCV) in highest four bits\r |
| 460 | (r11 : Temporary register)\r |
| 461 | \r |
| 462 | Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode.\r |
| 463 | r9 is not used intentionally, because AAPCS defines it as "platform register", so it's\r |
| 464 | reserved in some systems.\r |
| 465 | \r |
| 466 | \r |
| 467 | Thanks to...\r |
| 468 | ------------\r |
| 469 | \r |
| 470 | * All the previous code-generating assembler cpu core guys!\r |
| 471 | Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson\r |
| 472 | Karl Stenerud and Bart Trzynadlowski\r |
| 473 | \r |
| 474 | * Charles Macdonald, for researching just about every console ever\r |
| 475 | * MameDev+FBA, for keeping on going and going and going\r |
| 476 | \r |
| 477 | \r |
| 478 | What's New\r |
| 479 | ----------\r |
| 480 | v0.0099 notaz\r |
| 481 | * Cyclone no longer uses r9, because AAPCS defines it as "platform register",\r |
| 482 | so it's reserved in some systems.\r |
| 483 | * Made SPLIT_MOVEL_PD to affect MOVEM too.\r |
| 484 | \r |
| 485 | v0.0088 notaz\r |
| 486 | - Reduced amount of code in opcode handlers by ~23% by doing the following:\r |
| 487 | - Removed duplicate opcode handlers\r |
| 488 | - Optimized code to use less ARM instructions\r |
| 489 | - Merged some duplicate handler endings\r |
| 490 | + Cyclone now does better job avoiding pipeline interlocks.\r |
| 491 | + Replaced incorrect handler of DBT with proper one.\r |
| 492 | + Changed "MOVEA (An)+ An" behavior.\r |
| 493 | + Fixed flag behavior of ROXR, ASL, LSR and NBCD in certain situations.\r |
| 494 | Hopefully got them right now.\r |
| 495 | + Cyclone no longer sets most significant bits while pushing PC to stack.\r |
| 496 | Amiga Kickstart depends on this.\r |
| 497 | + Added optional trace mode emulation.\r |
| 498 | + Added optional address error emulation.\r |
| 499 | + Additional functionality added for MAME and other ports (see config.h).\r |
| 500 | + Added return value for IrqCallback to make it suitable for emulating devices which\r |
| 501 | pass the vector number during interrupt acknowledge cycle. For usual autovector\r |
| 502 | processing this function must return CYCLONE_INT_ACK_AUTOVECTOR, so those who are\r |
| 503 | upgrading must add "return CYCLONE_INT_ACK_AUTOVECTOR;" to their IrqCallback functions.\r |
| 504 | * Updated documentation.\r |
| 505 | \r |
| 506 | v0.0086 notaz\r |
| 507 | + Cyclone now can be customized to better suit your project, see config.h .\r |
| 508 | + Added an option to compress the jumptable at compile-time. Must call CycloneInit()\r |
| 509 | at runtime to decompress it if enabled (see config.h).\r |
| 510 | + Added missing CHK opcode handler (used by SeaQuest DSV).\r |
| 511 | + Added missing TAS opcode handler (Gargoyles,Bubba N Stix,...). As in real genesis,\r |
| 512 | memory write-back phase is ignored (but can be enabled in config.h if needed).\r |
| 513 | + Added missing NBCD and TRAPV opcode handlers.\r |
| 514 | + Added missing addressing mode for CMP/EOR.\r |
| 515 | + Added some minor optimizations.\r |
| 516 | - Removed 216 handlers for 2927 opcodes which were generated for invalid addressing modes.\r |
| 517 | + Fixed flags for ASL, NEG, NEGX, DIVU, ADDX, SUBX, ROXR.\r |
| 518 | + Bugs fixed in MOVEP, LINK, ADDQ, DIVS handlers.\r |
| 519 | * Undocumented flags for CHK, ABCD, SBCD and NBCD are now emulated the same way as in Musashi.\r |
| 520 | + Added Uninitialized Interrupt emulation.\r |
| 521 | + Altered timing for about half of opcodes to match Musashi's.\r |
| 522 | \r |
| 523 | v0.0082 Reesy\r |
| 524 | + Change cyclone to clear cycles before returning when halted\r |
| 525 | + Added Irq call back function. This allows emulators to be notified\r |
| 526 | when cyclone has taken an interrupt allowing them to set internal flags\r |
| 527 | which can help fix timing problems.\r |
| 528 | \r |
| 529 | v0.0081 notaz\r |
| 530 | + .asm version was broken and did not compile with armasm. Fixed.\r |
| 531 | + Finished implementing Stop opcode. Now it really stops the processor.\r |
| 532 | \r |
| 533 | v0.0080 notaz\r |
| 534 | + Added real cmpm opcode, it was using eor handler before this.\r |
| 535 | Fixes Dune and Sensible Soccer.\r |
| 536 | \r |
| 537 | v0.0078 notaz\r |
| 538 | note: these bugs were actually found Reesy, I reimplemented these by\r |
| 539 | using his changelog as a guide.\r |
| 540 | + Fixed a problem with divu which was using long divisor instead of word.\r |
| 541 | Fixes gear switching in Top Gear 2.\r |
| 542 | + Fixed btst opcode, The bit to test should shifted a max of 31 or 7\r |
| 543 | depending on if a register or memory location is being tested.\r |
| 544 | + Fixed abcd,sbcd. They did bad decimal correction on invalid BCD numbers\r |
| 545 | Score counters in Streets of Rage level end work now.\r |
| 546 | + Changed flag handling of abcd,sbcd,addx,subx,asl,lsl,...\r |
| 547 | Some ops did not have flag handling at all.\r |
| 548 | Some ops must not change Z flag when result is zero, but they did.\r |
| 549 | Shift ops must not change X if shift count is zero, but they did.\r |
| 550 | There are probably still some flag problems left.\r |
| 551 | + Patially implemented Stop and Reset opcodes - Fixes Thunderforce IV\r |
| 552 | \r |
| 553 | v0.0075 notaz\r |
| 554 | + Added missing displacement addressing mode for movem (Fantastic Dizzy)\r |
| 555 | + Added OSP <-> A7 swapping code in opcodes, which change privilege mode\r |
| 556 | + Implemented privilege violation, line emulator and divide by zero exceptions\r |
| 557 | + Added negx opcode (Shining Force works!)\r |
| 558 | + Added overflow detection for divs/divu\r |
| 559 | \r |
| 560 | v0.0072 notaz\r |
| 561 | note: I could only get v0.0069 cyclone, so I had to implement these myself using Dave's\r |
| 562 | changelog as a guide.\r |
| 563 | + Fixed a problem with divs - remainder should be negative when divident is negative\r |
| 564 | + Added movep opcode (Sonic 3 works)\r |
| 565 | + Fixed a problem with DBcc incorrectly decrementing if the condition is true (Shadow of the Beast)\r |
| 566 | \r |
| 567 | v0.0069\r |
| 568 | + Added SBCD and the flags for ABCD/SBCD. Score and time now works in games such as\r |
| 569 | Rolling Thunder 2, Ghouls 'N Ghosts\r |
| 570 | + Fixed a problem with addx and subx with 8-bit and 16-bit values.\r |
| 571 | Ghouls 'N' Ghosts now works!\r |
| 572 | \r |
| 573 | v0.0068\r |
| 574 | + Added ABCD opcode (Streets of Rage works now!)\r |
| 575 | \r |
| 576 | v0.0067\r |
| 577 | + Added dbCC (After Burner)\r |
| 578 | + Added asr EA (Sonic 1 Boss/Labyrinth Zone)\r |
| 579 | + Added andi/ori/eori ccr (Altered Beast)\r |
| 580 | + Added trap (After Burner)\r |
| 581 | + Added special case for move.b (a7)+ and -(a7), stepping by 2\r |
| 582 | After Burner is playable! Eternal Champions shows more\r |
| 583 | + Fixed lsr.b/w zero flag (Ghostbusters)\r |
| 584 | Rolling Thunder 2 now works!\r |
| 585 | + Fixed N flag for .b and .w arithmetic. Golden Axe works!\r |
| 586 | \r |
| 587 | v0.0066\r |
| 588 | + Fixed a stupid typo for exg (orr r10,r10, not orr r10,r8), which caused alignment\r |
| 589 | crashes on Strider\r |
| 590 | \r |
| 591 | v0.0065\r |
| 592 | + Fixed a problem with immediate values - they weren't being shifted up correctly for some\r |
| 593 | opcodes. Spiderman works, After Burner shows a bit of graphics.\r |
| 594 | + Fixed a problem with EA:"110nnn" extension word. 32-bit offsets were being decoded as 8-bit\r |
| 595 | offsets by mistake. Castlevania Bloodlines seems fine now.\r |
| 596 | + Added exg opcode\r |
| 597 | + Fixed asr opcode (Sonic jumping left is fixed)\r |
| 598 | + Fixed a problem with the carry bit in rol.b (Marble Madness)\r |
| 599 | \r |
| 600 | v0.0064\r |
| 601 | + Added rtr\r |
| 602 | + Fixed addq/subq.l (all An opcodes are 32-bit) (Road Rash)\r |
| 603 | + Fixed various little timings\r |
| 604 | \r |
| 605 | v0.0063\r |
| 606 | + Added link/unlk opcodes\r |
| 607 | + Fixed various little timings\r |
| 608 | + Fixed a problem with dbCC opcode being emitted at set opcodes\r |
| 609 | + Improved long register access, the EA fetch now does ldr r0,[r7,r0,lsl #2] whenever\r |
| 610 | possible, saving 1 or 2 cycles on many opcodes, which should give a nice speed up.\r |
| 611 | + May have fixed N flag on ext opcode?\r |
| 612 | + Added dasm for link opcode.\r |
| 613 | \r |
| 614 | v0.0062\r |
| 615 | * I was a bit too keen with the Arithmetic opcodes! Some of them should have been abcd,\r |
| 616 | exg and addx. Removed the incorrect opcodes, pending re-adding them as abcd, exg and addx.\r |
| 617 | + Changed unknown opcodes to act as nops.\r |
| 618 | Not very technical, but fun - a few more games show more graphics ;)\r |
| 619 | \r |
| 620 | v0.0060\r |
| 621 | + Fixed divu (EA intro)\r |
| 622 | + Added sf (set false) opcode - SOR2\r |
| 623 | * Todo: pea/link/unlk opcodes\r |
| 624 | \r |
| 625 | v0.0059: Added remainder to divide opcodes.\r |
| 626 | \r |
| 627 | \r |