add a copy of Disa so Cyclone can be built standalone
[cyclone68000.git] / Cyclone / Cyclone.txt
CommitLineData
6003a768 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\r
15This code is licensed under the GNU General Public License version 2.0 and the MAME License.\r
16You can choose the license that has the most advantages for you.\r
17\r
18___________________________________________________________________________\r
19\r
20\r
21What is it?\r
22-----------\r
23\r
24Cyclone 68000 is an emulator for the 68000 microprocessor, written in ARM 32-bit assembly.\r
25It is aimed at chips such as ARM7 and ARM9 cores, StrongARM and XScale, to interpret 68000\r
26code as fast as possible.\r
27\r
28Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode.\r
29\r
30Developers:\r
31-----------\r
32\r
33Dave / FinalDave: emudave(atsymbol)gmail.com\r
34\r
35\r
36What's New\r
37----------\r
38v0.069\r
39 + Added SBCD and the flags for ABCD/SBCD. Score and time now works in games such as\r
40 Rolling Thunder 2, Ghouls 'N Ghosts\r
41 + Fixed a problem with addx and subx with 8-bit and 16-bit values.\r
42 Ghouls 'N' Ghosts now works!\r
43\r
44v0.068\r
45 + Added ABCD opcode (Streets of Rage works now!)\r
46\r
47v0.067\r
48 + Added dbCC (After Burner)\r
49 + Added asr EA (Sonic 1 Boss/Labyrinth Zone)\r
50 + Added andi/ori/eori ccr (Altered Beast)\r
51 + Added trap (After Burner)\r
52 + Added special case for move.b (a7)+ and -(a7), stepping by 2\r
53 After Burner is playable! Eternal Champions shows more\r
54 + Fixed lsr.b/w zero flag (Ghostbusters)\r
55 Rolling Thunder 2 now works!\r
56 + Fixed N flag for .b and .w arithmetic. Golden Axe works!\r
57\r
58v0.066\r
59 + Fixed a stupid typo for exg (orr r10,r10, not orr r10,r8), which caused alignment\r
60 crashes on Strider\r
61\r
62v0.065\r
63 + Fixed a problem with immediate values - they weren't being shifted up correctly for some\r
64 opcodes. Spiderman works, After Burner shows a bit of graphics.\r
65 + Fixed a problem with EA:"110nnn" extension word. 32-bit offsets were being decoded as 8-bit\r
66 offsets by mistake. Castlevania Bloodlines seems fine now.\r
67 + Added exg opcode\r
68 + Fixed asr opcode (Sonic jumping left is fixed)\r
69 + Fixed a problem with the carry bit in rol.b (Marble Madness)\r
70\r
71v0.064\r
72 + Added rtr\r
73 + Fixed addq/subq.l (all An opcodes are 32-bit) (Road Rash)\r
74 + Fixed various little timings\r
75\r
76v0.063\r
77 + Added link/unlk opcodes\r
78 + Fixed various little timings\r
79 + Fixed a problem with dbCC opcode being emitted at set opcodes\r
80 + Improved long register access, the EA fetch now does ldr r0,[r7,r0,lsl #2] whenever\r
81 possible, saving 1 or 2 cycles on many opcodes, which should give a nice speed up.\r
82 + May have fixed N flag on ext opcode?\r
83 + Added dasm for link opcode.\r
84\r
85v0.062\r
86 * I was a bit too keen with the Arithmetic opcodes! Some of them should have been abcd,\r
87 exg and addx. Removed the incorrect opcodes, pending re-adding them as abcd, exg and addx.\r
88 + Changed unknown opcodes to act as nops.\r
89 Not very technical, but fun - a few more games show more graphics ;)\r
90\r
91v0.060\r
92 + Fixed divu (EA intro)\r
93 + Added sf (set false) opcode - SOR2\r
94 * Todo: pea/link/unlk opcodes\r
95\r
96v0.059: Added remainder to divide opcodes.\r
97\r
98\r
99ARM Register Usage\r
100------------------\r
101\r
102See source code for up to date of register usage, however a summary is here:\r
103\r
104 r0-3: Temporary registers\r
105 r4 : Current PC + Memory Base (i.e. pointer to next opcode)\r
106 r5 : Cycles remaining\r
107 r6 : Pointer to Opcode Jump table\r
108 r7 : Pointer to Cpu Context\r
109 r8 : Current Opcode\r
110 r9 : Flags (NZCV) in highest four bits\r
111 (r10 : Temporary source value or Memory Base)\r
112 (r11 : Temporary register)\r
113\r
114\r
115How to Compile\r
116--------------\r
117\r
118Like Starscream and A68K, Cyclone uses a 'Core Creator' program which calculates and outputs\r
119all possible 68000 Opcodes and a jump table into files called Cyclone.s and .asm\r
120It then assembles these files into Cyclone.o and .obj\r
121\r
122Cyclone.o is the GCC assembled version and Cyclone.obj is the Microsoft assembled version.\r
123\r
124First unzip "Cyclone.zip" into a "Cyclone" directory.\r
125If you are compiling for Windows CE, find ARMASM.EXE (the Microsoft ARM assembler) and\r
126put it in the directory as well or put it on your path.\r
127\r
128Open up Cyclone.dsw in Visual Studio 6.0, compile and run the project.\r
129Cyclone.obj and Cyclone.o will be created.\r
130\r
131Compiling without Visual C++\r
132----------------------------\r
133If you aren't using Visual C++, it still shouldn't be too hard to compile, just get a C compiler,\r
134compile all the CPPs and C file, link them into an EXE, and run the exe.\r
135\r
136 e.g. gcc Main.cpp OpAny.cpp OpArith.cpp OpBranch.cpp OpLogic.cpp OpMove.cpp Disa.c\r
137 Main.exe\r
138\r
139\r
140Adding to your project\r
141----------------------\r
142\r
143To add Cyclone to you project, add Cyclone.o or obj, and include Cyclone.h\r
144There is one structure: 'struct Cyclone', and one function: CycloneRun\r
145\r
146Don't worry if this seem very minimal - its all you need to run as many 68000s as you want.\r
147It works with both C and C++.\r
148\r
149Byteswapped Memory\r
150------------------\r
151\r
152If you have used Starscream, A68K or Turbo68K or similar emulators you'll be familiar with this!\r
153\r
154Any memory which the 68000 can access directly must be have every two bytes swapped around.\r
155This is to speed up 16-bit memory accesses, because the 68000 has Big-Endian memory\r
156and ARM has Little-Endian memory.\r
157\r
158Now you may think you only technically have to byteswap ROM, not RAM, because\r
15916-bit RAM reads go through a memory handler and you could just return (mem[a]<<8) | mem[a+1].\r
160\r
161This would work, but remember some systems can execute code from RAM as well as ROM, and\r
162that would fail.\r
163So it's best to use byteswapped ROM and RAM if the 68000 can access it directly.\r
164It's also faster for the memory handlers, because you can do this:\r
165 \r
166 return *(unsigned short *)(mem+a)\r
167\r
168\r
169Declaring a Memory handlers\r
170---------------------------\r
171\r
172Before you can reset or execute 68000 opcodes you must first set up a set of memory handlers.\r
173There are 7 functions you have to set up per CPU, like this:\r
174\r
175 static unsigned int MyCheckPc(unsigned int pc)\r
176 static unsigned char MyRead8 (unsigned int a)\r
177 static unsigned short MyRead16 (unsigned int a)\r
178 static unsigned int MyRead32 (unsigned int a)\r
179 static void MyWrite8 (unsigned int a,unsigned char d)\r
180 static void MyWrite16(unsigned int a,unsigned short d)\r
181 static void MyWrite32(unsigned int a,unsigned int d)\r
182\r
183You can think of these functions representing the 68000's memory bus.\r
184The Read and Write functions are called whenever the 68000 reads or writes memory.\r
185For example you might set MyRead8 like this:\r
186\r
187 unsigned char MyRead8(unsigned int a)\r
188 {\r
189 a&=0xffffff; // Clip address to 24-bits\r
190\r
191 if (a<RomLength) return RomData[a^1]; // ^1 because the memory is byteswapped\r
192 if (a>=0xe00000) return RamData[(a^1)&0xffff];\r
193 return 0xff; // Out of range memory access\r
194 }\r
195\r
196The other 5 read/write functions are similar. I'll describe the CheckPc function later on.\r
197\r
198Declaring a CPU Context\r
199-----------------------\r
200\r
201To declare a CPU simple declare a struct Cyclone in your code. For example to declare\r
202two 68000s:\r
203\r
204 struct Cyclone MyCpu;\r
205 struct Cyclone MyCpu2;\r
206\r
207It's probably a good idea to initialise the memory to zero:\r
208\r
209 memset(&MyCpu, 0,sizeof(MyCpu));\r
210 memset(&MyCpu2,0,sizeof(MyCpu2));\r
211\r
212Next point to your memory handlers:\r
213\r
214 MyCpu.checkpc=MyCheckPc;\r
215 MyCpu.read8 =MyRead8;\r
216 MyCpu.read16 =MyRead16;\r
217 MyCpu.read32 =MyRead32;\r
218 MyCpu.write8 =MyWrite8;\r
219 MyCpu.write16=MyWrite16;\r
220 MyCpu.write32=MyWrite32;\r
221\r
222You also need to point the fetch handlers - for most systems out there you can just\r
223point them at the read handlers:\r
224 MyCpu.fetch8 =MyRead8;\r
225 MyCpu.fetch16 =MyRead16;\r
226 MyCpu.fetch32 =MyRead32;\r
227\r
228( Why a different set of function pointers for fetch?\r
229 Well there are some systems, the main one being CPS2, which return different data\r
230 depending on whether the 'fetch' line on the 68000 bus is high or low.\r
231 If this is the case, you can set up different functions for fetch reads.\r
232 Generally though you don't need to. )\r
233\r
234Now you are nearly ready to reset the 68000, except you need one more function: checkpc().\r
235\r
236The checkpc() function\r
237----------------------\r
238\r
239When Cyclone reads opcodes, it doesn't use a memory handler every time, this would be\r
240far too slow, instead it uses a direct pointer to ARM memory.\r
241For example if your Rom image was at 0x3000000 and the program counter was $206,\r
242Cyclone's program counter would be 0x3000206.\r
243\r
244The difference between an ARM address and a 68000 address is also stored in a variable called\r
245'membase'. In the above example it's 0x3000000. To retrieve the real PC, Cyclone just\r
246subtracts 'membase'.\r
247\r
248When a long jump happens, Cyclone calls checkpc(). If the PC is in a different bank,\r
249for example Ram instead of Rom, change 'membase', recalculate the new PC and return it:\r
250\r
251static int MyCheckPc(unsigned int pc)\r
252{\r
253 pc-=MyCpu.membase; // Get the real program counter\r
254\r
255 if (pc<RomLength) MyCpu.membase=(int)RomMem; // Jump to Rom\r
256 if (pc>=0xff0000) MyCpu.membase=(int)RamMem-0xff0000; // Jump to Ram\r
257\r
258 return MyCpu.membase+pc; // New program counter\r
259}\r
260\r
261Notice that the membase is always ARM address minus 68000 address.\r
262\r
263The above example doesn't consider mirrored ram, but for an example of what to do see\r
264PicoDrive (in Memory.cpp).\r
265\r
266\r
267Almost there - Reset the 68000!\r
268-------------------------------\r
269\r
270Next we need to Reset the 68000 to get the initial Program Counter and Stack Pointer. This\r
271is obtained from addresses 000000 and 000004.\r
272\r
273Here is code which resets the 68000 (using your memory handlers):\r
274\r
275 MyCpu.srh=0x27; // Set supervisor mode\r
276 MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer\r
277 MyCpu.membase=0;\r
278 MyCpu.pc=MyCpu.checkpc(MyCpu.read32(4)); // Get Program Counter\r
279\r
280And that's ready to go.\r
281\r
282\r
283Executing the 68000\r
284-------------------\r
285\r
286To execute the 68000, set the 'cycles' variable to the number of cycles you wish to execute,\r
287and then call CycloneRun with a pointer to the Cyclone structure.\r
288\r
289e.g.:\r
290 // Execute 1000 cycles on the 68000:\r
291 MyCpu.cycles=1000; CycloneRun(&MyCpu);\r
292\r
293For each opcode, the number of cycles it took is subtracted and the function returns when\r
294it reaches 0.\r
295\r
296e.g.\r
297 // Execute one instruction on the 68000:\r
298 MyCpu.cycles=0; CycloneRun(&MyCpu);\r
299 printf(" The opcode took %d cycles\n", -MyCpu.cycles);\r
300\r
301You should try to execute as many cycles as you can for maximum speed.\r
302The number actually executed may be slightly more than requested, i.e. cycles may come\r
303out with a small negative value:\r
304\r
305e.g.\r
306 int todo=12000000/60; // 12Mhz, for one 60hz frame\r
307 MyCpu.cycles=todo; CycloneRun(&MyCpu);\r
308 printf(" Actually executed %d cycles\n", todo-MyCpu.cycles);\r
309\r
310To calculate the number of cycles executed, use this formula:\r
311 Number of cycles requested - Cycle counter at the end\r
312\r
313\r
314Interrupts\r
315----------\r
316\r
317Causing an interrupt is very simple, simply set the irq variable in the Cyclone structure\r
318to the IRQ number.\r
319To lower the IRQ line, set it to zero.\r
320\r
321e.g:\r
322 MyCpu.irq=6; // Interrupt level 6\r
323 MyCpu.cycles=20000; CycloneRun(&MyCpu);\r
324\r
325Note that the interrupt is not actually processed until the next call to CycloneRun,\r
326and the interrupt may not be taken until the 68000 interrupt mask is changed to allow it.\r
327\r
328( The IRQ isn't checked on exiting from a memory handler: I don't think this will cause\r
329 me any trouble because I've never needed to trigger an interrupt from a memory handler,\r
330 but if someone needs to, let me know...)\r
331\r
332Accessing Cycle Counter\r
333-----------------------\r
334\r
335The cycle counter in the Cyclone structure is not, by default, updated before\r
336calling a memory handler, only at the end of an execution.\r
337\r
338If you do need to read the cycle counter inside memory handlers, there is a\r
339bitfield called 'Debug' in Cyclone/Main.cpp.\r
340You can try setting Debug to 1 and then making the Cyclone library.\r
341This will add extra instructions so Cyclone writes register r5 back into the structure.\r
342\r
343If you need to *modify* cycles in a memory handler, set Debug to 3, this will read back\r
344the cycle counter as well.\r
345\r
346Accessing Program Counter and registers\r
347---------------------------------------\r
348\r
349You can read Cyclone's registers directly from the structure at any time (as far as I know).\r
350\r
351The Program Counter, should you need to read or write it, is stored with membase\r
352added on. So use this formula to calculate the real 68000 program counter:\r
353\r
354 pc = MyCpu.pc - MyCpu.membase;\r
355\r
356The program counter is stored in r4 during execution, and isn't written back to the\r
357structure until the end of execution, which means you can't read normally real it from\r
358a memory handler.\r
359However you can try setting Debug to 4 and then making the Cyclone library, this will\r
360write back r4 to the structure.\r
361\r
362You can't access the flags from a handler either. I can't imagine why anyone would particularly\r
363need to do this, but if you do e-mail me and I'll add another bit to 'Debug' ;)\r
364\r
365\r
366Emulating more than one CPU\r
367---------------------------\r
368\r
369Since everything is based on the structures, emulating more than one cpu at the same time\r
370is just a matter of declaring more than one structures and timeslicing. You can emulate\r
371as many 68000s as you want.\r
372Just set up the memory handlers for each cpu and run each cpu for a certain number of cycles.\r
373\r
374e.g.\r
375 // Execute 1000 cycles on 68000 #1:\r
376 MyCpu.cycles=1000; CycloneRun(&MyCpu);\r
377\r
378 // Execute 1000 cycles on 68000 #2:\r
379 MyCpu2.cycles=1000; CycloneRun(&MyCpu2);\r
380\r
381\r
382Thanks to...\r
383------------\r
384\r
385* All the previous code-generating assembler cpu core guys!\r
386 Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson\r
387 and Bart Trzynadlowski\r
388\r
389* Charles Macdonald, for researching just about every console ever\r
390* MameDev+FBA, for keeping on going and going and going\r