initial import

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2006-12-19 20:53:21 +00:00
parent 2cadbd5e56
commit cc68a136aa
341 changed files with 180839 additions and 0 deletions

58
cpu/Cyclone/Cyclone.h Normal file
View file

@ -0,0 +1,58 @@
// Cyclone 68000 Emulator - Header File
// Most code (c) Copyright 2004 Dave, All rights reserved.
// Some coding/bugfixing was done by notaz
// Cyclone 68000 is free for non-commercial use.
// For commercial use, separate licencing terms must be obtained.
#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+PC
unsigned char srh; // [r7,#0x44] Status Register high (T_S__III)
unsigned char xc; // [r7,#0x45] Extend flag (____??X?)
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 vector; // [r7,#0x4c] IRQ vector (temporary)
unsigned int pad1[2];
int stopped; // [r7,#0x58] 1 == processor is in stopped state
int cycles; // [r7,#0x5c]
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 char (*read8 )(unsigned int a); // [r7,#0x68]
unsigned short (*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 char (*fetch8 )(unsigned int a); // [r7,#0x80]
unsigned short (*fetch16)(unsigned int a); // [r7,#0x84]
unsigned int (*fetch32)(unsigned int a); // [r7,#0x88]
void (*IrqCallback)(int int_level); // [r7,#0x8c] - optional irq callback function, see config.h
void (*ResetCallback)(); // [r7,#0x90] - if enabled in config.h, calls this whenever RESET opcode is encountered.
int (*UnrecognizedCallback)(); // [r7,#0x94] - if enabled in config.h, calls this whenever unrecognized opcode is encountered.
};
// used only if Cyclone was compiled with compressed jumptable, see config.h
void CycloneInit();
// 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); // auto-swaps a7<->osp if detects supervisor change
unsigned int CycloneGetSr(struct Cyclone *pcy);
#ifdef __cplusplus
} // End of extern "C"
#endif

473
cpu/Cyclone/Cyclone.txt Normal file
View file

@ -0,0 +1,473 @@
_____ __
/ ___/__ __ ____ / /___ ___ ___ ___________________
/ /__ / // // __// // _ \ / _ \/ -_) ___________________
\___/ \_, / \__//_/ \___//_//_/\__/ ___________________
/___/
___________________ ____ ___ ___ ___ ___
___________________ / __// _ \ / _ \ / _ \ / _ \
___________________ / _ \/ _ // // // // // // /
\___/\___/ \___/ \___/ \___/
___________________________________________________________________________
Cyclone 68000 (c) Copyright 2004 Dave. Free for non-commercial use
Homepage: http://www.finalburn.com/
Dave's e-mail: dev(atsymbol)finalburn.com
Replace (atsymbol) with @
Additional coding and bugfixes done by notaz, 2005, 2006
Homepage: http://mif.vu.lt/~grig2790/Cyclone/
e-mail: notasas(atsymbol)gmail.com
___________________________________________________________________________
What is it?
-----------
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.
Flags are mapped onto ARM flags whenever possible, which speeds up the processing of opcode.
What's New
----------
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.
The new stuff
-------------
Before using Cyclone, be sure to customize config.h to better suit your project. All options
are documented inside that file.
IrqCallback has been changed a bit, unlike in previous version, it should not return anything.
If you need to change IRQ level, you can safely do that in your handler.
Cyclone has changed quite a bit from the time when Dave stopped updating it, but the rest of
documentation still applies, so read it if you haven't done that yet. If you have, check the
"Accessing ..." parts.
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
r9 : Flags (NZCV) in highest four bits
(r10 : Temporary source value or Memory Base)
(r11 : Temporary register)
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 files called Cyclone.s and .asm
It then assembles these files into Cyclone.o and .obj
Cyclone.o is the GCC assembled version and Cyclone.obj is the Microsoft assembled version.
First unzip "Cyclone.zip" into a "Cyclone" directory.
If you are compiling for Windows CE, find ARMASM.EXE (the Microsoft ARM assembler) and
put it in the directory as well or put it on your path.
Open up Cyclone.dsw in Visual Studio 6.0, compile and run the project.
Cyclone.obj and Cyclone.o will be created.
Compiling without Visual C++
----------------------------
If you aren't using Visual C++, it still shouldn't be too hard to compile, just get a C compiler,
compile all the CPPs and C file, link them into an EXE, and run the exe.
e.g. gcc Main.cpp OpAny.cpp OpArith.cpp OpBranch.cpp OpLogic.cpp OpMove.cpp Disa.c
Main.exe
Adding to your project
----------------------
To add Cyclone to you project, add Cyclone.o or obj, and include Cyclone.h
There is one structure: 'struct Cyclone', and one function: CycloneRun
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.
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<RomLength) return RomData[a^1]; // ^1 because the memory is byteswapped
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. For example to declare
two 68000s:
struct Cyclone MyCpu;
struct Cyclone MyCpu2;
It's probably a good idea to initialise 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 you need one more function: 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 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<RomLength) MyCpu.membase=(int)RomMem; // Jump to Rom
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.cpp).
Almost there - Reset the 68000!
-------------------------------
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.srh=0x27; // Set supervisor mode
MyCpu.a[7]=MyCpu.read32(0); // Get Stack Pointer
MyCpu.membase=0;
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 0.
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.
( The IRQ isn't checked on exiting from a memory handler: I don't think this will cause
me any trouble because I've never needed to trigger an interrupt from a memory handler,
but if someone needs to, let me know...)
Accessing Cycle Counter
-----------------------
The cycle counter in the Cyclone structure is not, by default, updated before
calling a memory handler, only at the end of an execution.
*update*
Now this is configurable in config.h, there is no 'debug' variable.
Accessing Program Counter and registers
---------------------------------------
You can read Cyclone's registers directly from the structure at any time (as far as I know).
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;
The program counter is stored in r4 during execution, and isn't written back to the
structure until the end of execution, which means you can't read normally real it from
a memory handler.
*update*
Now this is configurable in config.h, there is no 'debug' variable. You can even enable
access to SR if you need. However changing PC in memhandlers is still not safe, you should
better clear cycles, wait untill CycloneRun() returns and then do whatever you need.
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);
Thanks to...
------------
* All the previous code-generating assembler cpu core guys!
Who are iirc... Neill Corlett, Neil Bradley, Mike Coates, Darren Olafson
and Bart Trzynadlowski
* Charles Macdonald, for researching just about every console ever
* MameDev+FBA, for keeping on going and going and going
-------------
Dave - 17th April 2004
notaz - 17th July 2006
Homepage: http://www.finalburn.com/
Dave's e-mail: dev(atsymbol)finalburn.com
Replace (atsymbol) with @

821
cpu/Cyclone/Disa/Disa.c Normal file
View file

@ -0,0 +1,821 @@
// Dave's Disa 68000 Disassembler
#ifndef __GNUC__
#pragma warning(disable:4115)
#endif
#include <stdio.h>
#include <string.h>
#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 (CPU_CALL *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;
}
// ================ 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<<i;
bit&=mask;
if (bit==0 || i==8)
{
// low to i-1 are a continuous section, add it:
char add[16]="";
int ad=low&8?'a':'d';
if (low==i-1) sprintf(add,"%c%d/", ad,low&7);
if (low< i-1) sprintf(add,"%c%d-%c%d/",ad,low&7, ad,(i-1)&7);
strcat(list,add);
low=i; // Next section
}
if (bit==0) low=i+1;
}
// Knock off trailing '/'
len=strlen(list);
if (len>0) if (list[len-1]=='/') list[len-1]=0;
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;
}
// ================ 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;
}
// ================ 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;
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&0x3f;
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&0xf1c0)==0x41c0) DisaLea(op);
if ((op&0xf9c0)==0x40c0) DisaMoveSr(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&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&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;
}

24
cpu/Cyclone/Disa/Disa.h Normal file
View file

@ -0,0 +1,24 @@
// Dave's Disa 68000 Disassembler
#ifdef __cplusplus
extern "C" {
#endif
#if defined(ARM) || defined(GP32) || !defined (__WINS__)
#define CPU_CALL
#else
#define CPU_CALL __fastcall
#endif
extern unsigned int DisaPc;
extern char *DisaText; // Text buffer to write in
extern unsigned short (CPU_CALL *DisaWord)(unsigned int a);
int DisaGetEa(char *t,int ea,int size);
int DisaGet();
#ifdef __cplusplus
} // End of extern "C"
#endif

414
cpu/Cyclone/Ea.cpp Normal file
View file

@ -0,0 +1,414 @@
#include "app.h"
// 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<<low; // This is the max we can do
if (ea>=8) needor=1; // Need to OR to access A0-7
if ((mask>>low)&8) if (ea&8) needor=0; // Ah - no we don't actually need to or, since the bit is high in r8
if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;)
ot(" and r%d,r8,#0x%.4x\n",r,mask);
if (needor) ot(" orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<<low);
// Find out amount to shift left:
lsl=shift-low;
if (lsl&&!noshift)
{
ot(" mov r%d,r%d,",r,r);
if (lsl>0) ot("lsl #%d\n", lsl);
else ot("lsr #%d\n",-lsl);
}
return 0;
}
// EaCalc - ARM Register 'a' = Effective Address
// Trashes r0,r2 and r3
// size values 0, 1, 2 ~ byte, word, long
int EaCalc(int a,int mask,int ea,int size,int top)
{
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)) 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<<size, strr=a;
int low=0,lsl,i;
if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1
EaCalcReg(2,ea,mask,0,0,1);
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
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 (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)
{
EaCalcReg(2,8,mask,0,0);
ot(" ldrsh r0,[r4],#2 ;@ Fetch offset\n");
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");
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);
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");
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");
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");
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);
Cycles+=4; // Extra cycles
return 0;
}
ot(" ldrh r2,[r4],#2 ;@ Fetch immediate value\n");
ot(" ldrh r0,[r4],#2\n");
ot(" orr r%d,r0,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
// Otherwise the ARM register v is sign extended, e.g. 0xc000 -> 0xffffc000
int EaRead(int a,int v,int ea,int size,int mask,int top)
{
char text[32]="";
int shift=0;
shift=32-(8<<size);
DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
if (ea<0x10)
{
int lsl=0,low=0,i;
if (size>=2||(size==0&&top)) {
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
}
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[size&3],v,a,lsl);
else if (lsl<0) ot(" ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl);
else ot(" ldr%s r%d,[r7,r%d]\n",Sarm[size&3],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 (v!=a || asl) ot(" mov r%d,r%d,asl #%d\n",v,a,asl);
ot("\n"); return 0;
}
if (a!=0) ot(" mov r0,r%d\n",a);
if (ea>=0x3a && ea<=0x3b) MemHandler(2,size); // Fetch
else MemHandler(0,size); // Read
if (v!=0 || shift) {
if (shift) ot(" mov r%d,r0,asl #%d\n",v,shift);
else ot(" mov r%d,r0\n",v);
}
if (top==0 && shift) ot(" mov r%d,r%d,asr #%d\n",v,v,shift);
ot("\n"); return 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)
{
char text[32]="";
int shift=0;
if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; }
if (top) shift=32-(8<<size);
DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
if (ea<0x10)
{
int lsl=0,low=0,i;
if (size>=2||(size==0&&top)) {
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 (a!=0 && v!=0) ot(" mov r0,r%d\n",a);
if (v!=1 || shift) ot(" mov r1,r%d,asr #%d\n",v,shift);
if (a!=0 && v==0) ot(" mov r0,r%d\n",a);
MemHandler(1,size); // Call write handler
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;
}

648
cpu/Cyclone/Main.cpp Normal file
View file

@ -0,0 +1,648 @@
#include "app.h"
static FILE *AsmFile=NULL;
static int CycloneVer=0x0086; // Version number of library
int *CyJump=NULL; // Jump table
int ms=USE_MS_SYNTAX; // If non-zero, output in Microsoft ARMASM format
char *Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1,2
char *Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2
int Cycles; // Current cycles for opcode
void ot(const char *format, ...)
{
va_list valist=NULL;
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);
va_start(valist,format);
if (AsmFile) vfprintf(AsmFile,format,valist);
va_end(valist);
}
void ltorg()
{
if (ms) ot(" LTORG\n");
else ot(" .ltorg\n");
}
// trashes all temp regs
static void PrintException(int ints)
{
if(!ints) {
ot(" ;@ Cause an Exception - Vector address in r0\n");
ot(" mov r11,r0\n");
}
ot(";@ swap OSP <-> A7?\n");
ot(" ldr r0,[r7,#0x44] ;@ Get SR high\n");
ot(" tst r0,#0x20\n");
ot(" bne no_sp_swap%i\n",ints);
ot(";@ swap OSP and A7:\n");
ot(" ldr r0,[r7,#0x3C] ;@ Get A7\n");
ot(" ldr r1,[r7,#0x48] ;@ Get OSP\n");
ot(" str r0,[r7,#0x48]\n");
ot(" str r1,[r7,#0x3C]\n");
ot("no_sp_swap%i%s\n",ints,ms?"":":");
ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
ot(" mov r1,r4,lsl #8\n");
ot(" sub r1,r1,r10,lsl #8 ;@ r1 = Old PC\n");
ot(" mov r1,r1,asr #8 ;@ push sign extended\n");
OpPush32();
OpPushSr(1);
ot(" mov r0,r11\n");
ot(";@ Read IRQ Vector:\n");
MemHandler(0,2);
if(ints) {
ot(" tst r0,r0 ;@ uninitialized int vector?\n");
ot(" moveq r0,#0x3c\n");
ot(" moveq lr,pc\n");
ot(" ldreq pc,[r7,#0x70] ;@ Call read32(r0) handler\n");
}
#if USE_CHECKPC_CALLBACK
ot(" add r0,r0,r10 ;@ r0 = Memory Base + New PC\n");
ot(" mov lr,pc\n");
ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
ot(" mov r4,r0\n");
#endif
ot("\n");
if(!ints) {
ot(" ldr r0,[r7,#0x44] ;@ Get SR high\n");
ot(" bic r0,r0,#0xd8 ;@ clear trace and unused flags\n");
ot(" orr r0,r0,#0x20 ;@ set supervisor mode\n");
ot(" strb r0,[r7,#0x44]\n");
}
}
// Trashes r0,r1
void CheckInterrupt(int op)
{
ot(";@ CheckInterrupt:\n");
ot(" ldr r0,[r7,#0x44]\n"); // same as ldrb r0,[r7,#0x47]
ot(" movs r0,r0,lsr #24 ;@ Get IRQ level (loading word is faster)\n");
ot(" beq NoInts%x\n",op);
ot(" cmp r0,#6 ;@ irq>6 ?\n");
ot(" ldrleb r1,[r7,#0x44] ;@ Get SR high: T_S__III\n");
ot(" andle r1,r1,#7 ;@ Get interrupt mask\n");
ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n");
ot(" blgt DoInterrupt\n");
ot("NoInts%x%s\n", op,ms?"":":");
ot("\n");
}
static void PrintFramework()
{
ot(";@ --------------------------- Framework --------------------------\n");
if (ms) ot("CycloneRun\n");
else ot("CycloneRun:\n");
ot(" stmdb sp!,{r4-r11,lr}\n");
ot(" mov r7,r0 ;@ r7 = Pointer to Cpu Context\n");
ot(" ;@ r0-3 = Temporary registers\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Flags (NZCV)\n");
ot(" ldr r6,=JumpTab ;@ 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 r0,[r7,#0x44]\n");
ot(" mov r9,r9,lsl #28 ;@ r9 = Flags 0xf0000000, cpsr format\n");
ot(" ;@ r10 = Source value / Memory Base\n");
ot("\n");
ot(";@ CheckInterrupt:\n");
ot(" movs r0,r0,lsr #24 ;@ Get IRQ level\n"); // same as ldrb r0,[r7,#0x47]
ot(" beq NoInts0\n");
ot(" cmp r0,#6 ;@ irq>6 ?\n");
ot(" ldrleb r1,[r7,#0x44] ;@ Get SR high: T_S__III\n");
ot(" andle r1,r1,#7 ;@ Get interrupt mask\n");
ot(" cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n");
ot(" blgt DoInterrupt\n");
ot(";@ Check if interrupt used up all the cycles:\n");
ot(" subs r5,r5,#0\n");
ot(" blt CycloneEndNoBack\n");
ot("NoInts0%s\n", ms?"":":");
ot("\n");
ot(";@ Check if our processor is in stopped state and jump to opcode handler if not\n");
ot(" ldr r0,[r7,#0x58]\n");
ot(" ldrh r8,[r4],#2 ;@ Fetch first opcode\n");
ot(" tst r0,r0 ;@ stopped?\n");
ot(" bne CycloneStopped\n");
ot(" ldr pc,[r6,r8,asl #2] ;@ Jump to opcode handler\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?"":":");
ot(" mov r9,r9,lsr #28\n");
ot(" str r4,[r7,#0x40] ;@ Save Current PC + Memory Base\n");
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
ot(" strb r9,[r7,#0x46] ;@ Save Flags (NZCV)\n");
ot(" ldmia sp!,{r4-r11,pc}\n");
ot("\n");
ot("CycloneStopped%s\n", ms?"":":");
ot(" mov r5,#0\n");
ot(" str r5,[r7,#0x5C] ;@ eat all cycles\n");
ot(" ldmia sp!,{r4-r11,pc} ;@ we are stopped, do nothing!\n");
ot("\n");
ltorg();
#if COMPRESS_JUMPTABLE
ot(";@ uncompress jump table\n");
if (ms) ot("CycloneInit\n");
else ot("CycloneInit:\n");
ot(" ldr r12,=JumpTab\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,=JumpTab\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();
ot("\n");
#else
ot(";@ do nothing\n");
if (ms) ot("CycloneInit\n");
else ot("CycloneInit:\n");
ot(" bx lr\n");
ot("\n");
#endif
if (ms) ot("CycloneSetSr\n");
else ot("CycloneSetSr:\n");
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");
ot(" and r2,r2,#0xa7 ;@ only nonzero bits\n");
ot(" strb r2,[r0,#0x44] ;@ set SR high\n");
ot(" bne setsr_noswap\n");
ot(" ldr r2,[r0,#0x3C] ;@ Get A7\n");
ot(" ldr r3,[r0,#0x48] ;@ Get OSP\n");
ot(" str r3,[r0,#0x3C]\n");
ot(" str r2,[r0,#0x48]\n");
ot("setsr_noswap%s\n",ms?"":":");
ot(" mov r2,r1,lsr #3\n");
ot(" strb r2,[r0,#0x45] ;@ 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");
if (ms) ot("CycloneGetSr\n");
else ot("CycloneGetSr:\n");
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(" ldrb r1,[r0,#0x45] ;@ the X flag\n");
ot(" tst r1,#2\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(";@ DoInterrupt - r0=IRQ number\n");
ot("DoInterrupt%s\n", ms?"":":");
ot(" stmdb sp!,{lr} ;@ Push ARM return address\n");
ot(";@ Get IRQ Vector address:\n");
ot(" mov r0,r0,asl #2\n");
ot(" add r11,r0,#0x60\n");
PrintException(1);
ot(" ldrb r0,[r7,#0x47] ;@ IRQ\n");
ot(" mov r2,#0\n");
ot(" orr r1,r0,#0x20 ;@ Supervisor mode + IRQ number\n");
ot(" strb r1,[r7,#0x44] ;@ Put SR high\n");
ot(";@ Clear stopped states:\n");
ot(" str r2,[r7,#0x58]\n");
ot(" sub r5,r5,#%d ;@ Subtract cycles\n",44);
ot("\n");
#if USE_INT_ACK_CALLBACK
#if INT_ACK_NEEDS_STUFF
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
ot(" mov r1,r9,lsr #28\n");
ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
#endif
ot(" ldr r11,[r7,#0x8c] ;@ IrqCallback\n");
ot(" tst r11,r11\n");
ot(" movne lr,pc\n");
ot(" movne pc,r11 ;@ call IrqCallback if it is defined\n");
#if INT_ACK_CHANGES_STUFF
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" mov r9,r9,lsl #28\n");
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
#endif
#else // not USE_INT_ACK_CALLBACK
ot(";@ Clear irq:\n");
ot(" strb r1,[r7,#0x47]\n");
#endif
ot(" ldmia sp!,{pc} ;@ Return\n");
ot("\n");
ot("Exception%s\n", ms?"":":");
ot("\n");
ot(" stmdb sp!,{lr} ;@ Preserve ARM return address\n");
PrintException(0);
ot(" ldmia sp!,{pc} ;@ Return\n");
ot("\n");
}
// ---------------------------------------------------------------------------
// Call Read(r0), Write(r0,r1) or Fetch(r0)
// Trashes r0-r3,r12,lr
int MemHandler(int type,int size)
{
int func=0;
func=0x68+type*0xc+(size<<2); // Find correct offset
#if MEMHANDLERS_NEED_PC
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
#endif
#if MEMHANDLERS_NEED_FLAGS
ot(" mov r3,r9,lsr #28\n");
ot(" strb r3,[r7,#0x46] ;@ Save Flags (NZCV)\n");
#endif
#if MEMHANDLERS_NEED_CYCLES
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
#endif
ot(" mov lr,pc\n");
ot(" ldr pc,[r7,#0x%x] ;@ Call ",func);
// Document what we are calling:
if (type==0) ot("read");
if (type==1) ot("write");
if (type==2) ot("fetch");
if (type==1) ot("%d(r0,r1)",8<<size);
else ot("%d(r0)", 8<<size);
ot(" handler\n");
#if MEMHANDLERS_CHANGE_CYCLES
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
#endif
#if MEMHANDLERS_CHANGE_FLAGS
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" mov r9,r9,lsl #28\n");
#endif
#if MEMHANDLERS_CHANGE_PC
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
#endif
return 0;
}
static void PrintOpcodes()
{
int op=0;
printf("Creating Opcodes: [");
ot(";@ ---------------------------- Opcodes ---------------------------\n");
// Emit null opcode:
ot("Op____%s ;@ Called if an opcode is not recognised\n", ms?"":":");
ot(" sub r4,r4,#2\n");
#if USE_UNRECOGNIZED_CALLBACK
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
ot(" mov r1,r9,lsr #28\n");
ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
ot(" ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
ot(" tst r11,r11\n");
ot(" movne lr,pc\n");
ot(" movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
ot(" mov r9,r9,lsl #28\n");
ot(" tst r0,r0\n");
ot(" moveq r0,#0x10\n");
ot(" bleq Exception\n");
#else
ot(" mov r0,#0x10\n");
ot(" bl Exception\n");
#endif
Cycles=34;
OpEnd();
// Unrecognised a-line and f-line opcodes throw an exception:
ot("Op__al%s ;@ Unrecognised a-line opcode\n", ms?"":":");
ot(" sub r4,r4,#2\n");
#if USE_AFLINE_CALLBACK
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
ot(" mov r1,r9,lsr #28\n");
ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
ot(" ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
ot(" tst r11,r11\n");
ot(" movne lr,pc\n");
ot(" movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
ot(" mov r9,r9,lsl #28\n");
ot(" tst r0,r0\n");
ot(" moveq r0,#0x28\n");
ot(" bleq Exception\n");
#else
ot(" mov r0,#0x28\n");
ot(" bl Exception\n");
#endif
Cycles=4;
OpEnd();
ot("Op__fl%s ;@ Unrecognised f-line opcode\n", ms?"":":");
ot(" sub r4,r4,#2\n");
#if USE_AFLINE_CALLBACK
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
ot(" mov r1,r9,lsr #28\n");
ot(" strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
ot(" str r5,[r7,#0x5c] ;@ Save Cycles\n");
ot(" ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
ot(" tst r11,r11\n");
ot(" movne lr,pc\n");
ot(" movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
ot(" mov r9,r9,lsl #28\n");
ot(" tst r0,r0\n");
ot(" moveq r0,#0x2c\n");
ot(" bleq Exception\n");
#else
ot(" mov r0,#0x2c\n");
ot(" bl Exception\n");
#endif
Cycles=4;
OpEnd();
for (op=0;op<0x10000;op++)
{
if ((op&0xfff)==0) { printf("%x",op>>12); fflush(stdout); } // Update progress
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");
#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;
// space for decompressed table
ot(ms?" area |.data|, data\n":" .data\n .align 4\n\n");
ot("JumpTab%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<len;i++)
{
op=CyJump[i];
for(u=i-1; u>=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
ot("\n");
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("JumpTab%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<len;i++)
{
op=CyJump[i];
if(op>=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;
char *name="Cyclone.s";
// 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-2006 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
if (ms)
{
ot(" area |.text|, code\n");
ot(" export CycloneInit\n");
ot(" export CycloneRun\n");
ot(" export CycloneSetSr\n");
ot(" export CycloneGetSr\n");
ot(" export CycloneVer\n");
ot("\n");
ot("CycloneVer dcd 0x%.4x\n",CycloneVer);
}
else
{
ot(" .global CycloneInit\n");
ot(" .global CycloneRun\n");
ot(" .global CycloneSetSr\n");
ot(" .global CycloneGetSr\n");
ot(" .global CycloneVer\n");
ot("CycloneVer: .long 0x%.4x\n",CycloneVer);
}
ot("\n");
PrintFramework();
PrintOpcodes();
PrintJumpTable();
if (ms) ot(" END\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;
}

119
cpu/Cyclone/OpAny.cpp Normal file
View file

@ -0,0 +1,119 @@
#include "app.h"
static unsigned char OpData[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static unsigned short CPU_CALL 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)
{
Cycles=0;
OpUse(op,op); // This opcode obviously uses this handler
ot("Op%.4x%s\n", op, ms?"":":");
}
void OpEnd()
{
ot(" ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
ot(" subs r5,r5,#%d ;@ Subtract cycles\n",Cycles);
ot(" ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
ot(" b CycloneEnd\n");
ot("\n");
}
int OpBase(int op,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 (ea>=0x18 && ea<0x28 && (ea&7)==7) 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,r9,#0xb0000000 ;@ for old Z\n");
ot(" mrs r9,cpsr ;@ r9=flags\n");
if (specialz) ot(" andeq r9,r9,r2 ;@ fix Z\n");
if (subtract) ot(" eor r9,r9,#0x20000000 ;@ Invert carry\n");
if (xbit)
{
ot(" mov r2,r9,lsr #28\n");
ot(" strb r2,[r7,#0x45] ;@ Save X bit\n");
}
return 0;
}
// -----------------------------------------------------------------
void OpAny(int op)
{
memset(OpData,0x33,sizeof(OpData));
OpData[0]=(unsigned char)(op>>8);
OpData[1]=(unsigned char)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);
}

758
cpu/Cyclone/OpArith.cpp Normal file
View file

@ -0,0 +1,758 @@
#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;
// 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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
EaCalc(10,0x0000, sea,size,1);
EaRead(10, 10, sea,size,0,1);
EaCalc(11,0x003f, tea,size,1);
EaRead(11, 0, tea,size,0x003f,1);
ot(";@ Do arithmetic:\n");
if (type==0) ot(" orr r1,r0,r10\n");
if (type==1) ot(" and r1,r0,r10\n");
if (type==2) ot(" subs r1,r0,r10 ;@ Defines NZCV\n");
if (type==3) ot(" adds r1,r0,r10 ;@ Defines NZCV\n");
if (type==5) ot(" eor r1,r0,r10\n");
if (type==6) ot(" cmp r0,r10 ;@ Defines NZCV\n");
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();
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,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);
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
EaCalc(10,0x003f, ea,size,1);
EaRead(10, 0, ea,size,0x003f,1);
shift=32-(8<<size);
if (num!=8)
{
int lsr=9-shift;
if (lsr>=0) ot(" mov r2,r8,lsr #%d ;@ Get quick value\n", lsr);
else ot(" mov r2,r8,lsl #%d ;@ Get quick value\n",-lsr);
ot(" and r2,r2,#0x%.4x\n",7<<shift);
ot("\n");
strcpy(count,"r2");
}
if (num==8) sprintf(count,"#0x%.4x",8<<shift);
if (type==0) ot(" adds r1,r0,%s\n",count);
if (type==1) ot(" subs r1,r0,%s\n",count);
if ((ea&0x38)!=0x08) OpGetFlags(type,1);
ot("\n");
EaWrite(10, 1, ea,size,0x003f,1);
OpEnd();
return 0;
}
// --------------------- Opcodes 0x8000+ ---------------------
// 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)
int OpArithReg(int op)
{
int use=0;
int type=0,size=0,dir=0,rea=0,ea=0;
type=(op>>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);
use&=~0x0e00; // Use same opcode for Dn
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
ot(";@ Get r10=EA r11=EA value\n");
EaCalc(10,0x003f, ea,size,1);
EaRead(10, 11, ea,size,0x003f,1);
ot(";@ Get r0=Register r1=Register value\n");
EaCalc( 0,0x0e00,rea,size,1);
EaRead( 0, 1,rea,size,0x0e00,1);
ot(";@ Do arithmetic:\n");
if (type==0) ot(" orr ");
if (type==1) ot(" subs ");
if (type==4) ot(" and ");
if (type==5) ot(" adds ");
if (dir) ot("r1,r11,r1\n");
else ot("r1,r1,r11\n");
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 (dir) EaWrite(10, 1, ea,size,0x003f,1);
else EaWrite( 0, 1,rea,size,0x0e00,1);
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();
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);
use&=~0x0e00; // Use same for all registers
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
if(type) Cycles=54;
else Cycles=sign?158:140;
EaCalc(10,0x003f, ea, 1);
EaRead(10, 10, ea, 1,0x003f);
EaCalc (0,0x0e00,rea, 2,1);
EaRead (0, 2,rea, 2,0x0e00,1);
if (type==0) // div
{
// the manual says C is always cleared, but neither Musashi nor FAME do that
//ot(" bic r9,r9,#0x20000000 ;@ always clear C\n");
ot(" tst r10,r10\n");
ot(" beq divzero%.4x ;@ division by zero\n",op);
ot("\n");
if (sign)
{
ot(" mov r11,#0 ;@ r11 = 1 or 2 if the result is negative\n");
ot(" orrmi r11,r11,#1\n");
ot(" rsbmi r10,r10,#0 ;@ Make r10 positive\n");
ot("\n");
ot(" tst r2,r2\n");
ot(" orrmi r11,r11,#2\n");
ot(" rsbmi r2,r2,#0 ;@ Make r2 positive\n");
ot("\n");
}
else
{
ot(" mov r10,r10,lsl #16 ;@ use only 16 bits of divisor\n");
ot(" mov r10,r10,lsr #16\n");
}
ot(";@ Divide r2 by r10\n");
ot(" mov r3,#0\n");
ot(" mov r1,r10\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,r10\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,r11,#1\n");
ot(" teq r1,r11,lsr #1\n");
ot(" rsbne r3,r3,#0 ;@ negate if quotient is negative\n");
ot(" tst r11,#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 r9,r9,#0x10000000 ;@ set overflow flag\n");
ot(" bne endofop%.4x ;@ overflow!\n",op);
}
else
{
// overflow check
ot(" movs r1,r3,lsr #16 ;@ check for overflow condition\n");
ot(" orrne r9,r9,#0x10000000 ;@ set overflow flag\n");
ot(" bne endofop%.4x ;@ overflow!\n",op);
}
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)
{
char *shift="asr";
ot(";@ Get 16-bit signs right:\n");
if (sign==0) { ot(" mov r10,r10,lsl #16\n"); shift="lsr"; }
ot(" mov r2,r2,lsl #16\n");
if (sign==0) ot(" mov r10,r10,lsr #16\n");
ot(" mov r2,r2,%s #16\n",shift);
ot("\n");
ot(" mul r1,r2,r10\n");
ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
OpGetFlags(0,0);
}
ot("\n");
EaWrite(0, 1,rea, 2,0x0e00,1);
ot("endofop%.4x%s\n",op,ms?"":":");
OpEnd();
ot("divzero%.4x%s\n",op,ms?"":":");
ot(" mov r0,#0x14 ;@ Divide by zero\n");
ot(" bl Exception\n");
Cycles+=38;
OpEnd();
ot("\n");
return 0;
}
// Get X Bit into carry - trashes r2
int GetXBit(int subtract)
{
ot(";@ Get X bit:\n");
ot(" ldrb r2,[r7,#0x45]\n");
if (subtract) ot(" mvn r2,r2,lsl #28 ;@ Invert it\n");
else ot(" mov r2,r2,lsl #28\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,addr=0,dea=0;
type=(op>>14)&1; // sbcd/abcd
dea =(op>> 9)&7;
addr=(op>> 3)&1;
sea = op &7;
if (addr) { sea|=0x20; dea|=0x20; }
use=op&~0x0e07; // Use same opcode for all registers..
if (sea==0x27||dea==0x27) use=op; // ..except -(a7)
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=6;
EaCalc( 0,0x0007, sea,0,1);
EaRead( 0, 10, sea,0,0x0007,1);
EaCalc(11,0x0e00, dea,0,1);
EaRead(11, 1, dea,0,0x0e00,1);
ot(" bic r9,r9,#0xb1000000 ;@ clear all flags except old Z\n");
if (type)
{
ot(" ldrb r0,[r7,#0x45] ;@ Get X bit\n");
ot(" mov r3,#0x00f00000\n");
ot(" and r2,r3,r1,lsr #4\n");
ot(" tst r0,#2\n");
ot(" and r0,r3,r10,lsr #4\n");
ot(" add r0,r0,r2\n");
ot(" addne r0,r0,#0x00100000\n");
// ot(" tst r0,#0x00800000\n");
// ot(" orreq r9,r9,#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,r10,lsr #28\n");
ot(" add r0,r0,r2,lsl #24\n");
ot(" cmp r0,#0x09900000\n");
ot(" orrhi r9,r9,#0x20000000 ;@ C\n");
ot(" subhi r0,r0,#0x0a000000\n");
// ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n");
// ot(" orr r9,r9,r3,lsl #4 ;@ V\n");
ot(" movs r0,r0,lsl #4\n");
ot(" orrmi r9,r9,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does
ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n");
}
else
{
ot(" ldrb r0,[r7,#0x45] ;@ Get X bit\n");
ot(" mov r3,#0x00f00000\n");
ot(" and r2,r3,r10,lsr #4\n");
ot(" tst r0,#2\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 r9,r9,#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,r10,lsr #28\n");
ot(" sub r0,r0,r2,lsl #24\n");
ot(" cmp r0,#0x09900000\n");
ot(" orrhi r9,r9,#0xa0000000 ;@ N and C\n");
ot(" addhi r0,r0,#0x0a000000\n");
// ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n");
// ot(" orr r9,r9,r3,lsl #4 ;@ V\n");
ot(" movs r0,r0,lsl #4\n");
// ot(" orrmi r9,r9,#0x80000000 ;@ Undefined N behavior\n");
ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n");
}
ot(" mov r2,r9,lsr #28\n");
ot(" strb r2,[r7,#0x45] ;@ Save X bit\n");
EaWrite(11, 0, dea,0,0x0e00,1);
OpEnd();
return 0;
}
// 01008000 00eeeeee - nbcd <ea>
int OpNbcd(int op)
{
int use=0;
int ea=0;
ea=op&0x3f;
if(EaCanWrite(ea)==0||EaAn(ea)) return 1;
use=OpBase(op);
if(op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=6;
if(ea >= 8) Cycles+=2;
EaCalc(10,0x3f, ea,0,1);
EaRead(10, 0, ea,0,0x3f,1);
// this is rewrite of Musashi's code
ot(" ldrb r2,[r7,#0x45]\n");
ot(" tst r2,#2\n");
ot(" mov r2,r0\n");
ot(" addne r2,r0,#0x01000000 ;@ add X\n");
ot(" rsbs r1,r2,#0x9a000000 ;@ do arithmetic\n");
ot(" bic r9,r9,#0xb0000000 ;@ clear all flags, except Z\n");
ot(" orrmi r9,r9,#0x80000000 ;@ N\n");
ot(" cmp r1,#0x9a000000\n");
ot(" beq finish%.4x\n",op);
ot("\n");
ot(" mvn r3,r9,lsr #3 ;@ Undefined V behavior\n",op);
ot(" and r2,r1,#0x0f000000\n");
ot(" cmp r2,#0x0a000000\n");
ot(" andeq r1,r1,#0xf0000000\n");
ot(" addeq r1,r1,#0x10000000\n");
ot(" and r3,r3,r1,lsr #3 ;@ Undefined V behavior part II\n",op);
ot(" tst r1,r1\n");
ot(" orr r9,r9,r3 ;@ save V\n",op);
ot(" bicne r9,r9,#0x40000000 ;@ Z\n");
ot(" orr r9,r9,#0x20000000 ;@ C\n");
ot("\n");
EaWrite(10, 1, ea,0,0x3f,1);
ot("finish%.4x%s\n",op,ms?"":":");
ot(" mov r2,r9,lsr #28\n");
ot(" strb r2, [r7,#0x45]\n");
OpEnd();
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;
// 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);
use&=~0x0e00; // Use same opcode for An
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=(size==2)?6:8;
if(size==2&&(sea<0x10||sea==0x3c)) Cycles+=2;
if(type==1) Cycles=6;
EaCalc ( 0,0x003f, sea,size);
EaRead ( 0, 10, sea,size,0x003f);
EaCalc ( 0,0x0e00, dea,2,1);
EaRead ( 0, 1, dea,2,0x0e00);
if (type==0) ot(" sub r1,r1,r10\n");
if (type==1) ot(" cmp r1,r10 ;@ Defines NZCV\n");
if (type==1) OpGetFlags(1,0); // Get Cmp flags
if (type==2) ot(" add r1,r1,r10\n");
ot("\n");
if (type!=1) EaWrite( 0, 1, dea,2,0x0e00,1);
OpEnd();
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;
type=(op>>12)&5;
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||dea==0x27)) use=op; // ___x.b -(a7)
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
if(size>=2) Cycles+=4;
if(sea>=0x10) Cycles+=2;
ot(";@ Get r10=EA r11=EA value\n");
EaCalc( 0,0x0007,sea,size,1);
EaRead( 0, 11,sea,size,0x0007,1);
ot(";@ Get r0=Register r1=Register value\n");
EaCalc( 0,0x0e00,dea,size,1);
EaRead( 0, 1,dea,size,0x0e00,1);
ot(";@ Do arithmetic:\n");
GetXBit(type==1);
if (type==5 && size<2)
{
ot(";@ Make sure the carry bit will tip the balance:\n");
ot(" mvn r2,#0\n");
ot(" orr r11,r11,r2,lsr #%i\n",(size==0)?8:16);
ot("\n");
}
if (type==1) ot(" sbcs r1,r1,r11\n");
if (type==5) ot(" adcs r1,r1,r11\n");
ot(" orr r3,r9,#0xb0000000 ;@ for old Z\n");
OpGetFlags(type==1,1,0); // subtract
if (size<2) {
ot(" movs r2,r1,lsr #%i\n", size?16:24);
ot(" orreq r9,r9,#0x40000000 ;@ add potentially missed Z\n");
}
ot(" andeq r9,r9,r3 ;@ fix Z\n");
ot("\n");
ot(";@ Save result:\n");
EaWrite( 0, 1, dea,size,0x0e00,1);
OpEnd();
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;
// 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);
use&=~0x0e00; // Use 1 handler for register d0-7
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
if(eor) {
if(ea>8) Cycles+=4;
if(size>=2) Cycles+=4;
} else {
if(size>=2) Cycles+=2;
}
ot(";@ Get EA into r10 and value into r0:\n");
EaCalc (10,0x003f, ea,size,1);
EaRead (10, 0, ea,size,0x003f,1);
ot(";@ Get register operand into r1:\n");
EaCalc (1, 0x0e00, rea,size,1);
EaRead (1, 1, rea,size,0x0e00,1);
ot(";@ Do arithmetic:\n");
if (eor==0) ot(" cmp r1,r0\n");
if (eor)
{
ot(" eor r1,r0,r1\n");
ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
}
OpGetFlags(eor==0,0); // Cmp like subtract
ot("\n");
if (eor) EaWrite(10, 1,ea,size,0x003f,1);
OpEnd();
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;
// 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||dea==0x1f)) use=op; // ..except (a7)+
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
ot(";@ Get src operand into r10:\n");
EaCalc (0,0x000f, sea,size,1);
EaRead (0, 10, sea,size,0x000f,1);
ot(";@ Get dst operand into r0:\n");
EaCalc (0,0x1e00, dea,size,1);
EaRead (0, 0, dea,size,0x1e00,1);
ot(" cmp r0,r10\n");
OpGetFlags(1,0); // Cmp like subtract
OpEnd();
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);
use&=~0x0e00; // Use 1 handler for register d0-7
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=10;
ot(";@ Get EA into r10 and value into r0:\n");
EaCalc (10,0x003f, ea,size,1);
EaRead (10, 0, ea,size,0x003f,1);
ot(";@ Get register operand into r1:\n");
EaCalc (1, 0x0e00, rea,size,1);
EaRead (1, 1, rea,size,0x0e00,1);
ot(";@ get flags, including undocumented ones\n");
ot(" and r3,r9,#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(" cmp r1,r0\n");
ot(" bicgt r9,r9,#0x80000000 ;@ N\n");
ot(" bgt chktrap%.4x\n",op);
ot(";@ old N remains\n");
ot(" bic r9,r9,#0x80000000 ;@ N\n");
ot(" orr r9,r9,r3\n");
OpEnd();
ot("chktrap%.4x%s ;@ CHK exception:\n",op,ms?"":":");
ot(" mov r0,#0x18\n");
ot(" bl Exception\n");
Cycles+=40;
OpEnd();
return 0;
}

434
cpu/Cyclone/OpBranch.cpp Normal file
View file

@ -0,0 +1,434 @@
#include "app.h"
#if USE_CHECKPC_CALLBACK
static void CheckPc()
{
ot(";@ Check Memory Base+pc (r4)\n");
ot(" add lr,pc,#4\n");
ot(" mov r0,r4\n");
ot(" ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
ot(" mov r4,r0\n");
ot("\n");
}
#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 - assumes r10=Memory Base - 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(" add r4,r0,r10 ;@ r4=Memory Base+PC\n");
ot("\n");
CheckPc();
}
int OpTrap(int op)
{
int use=0;
use=op&~0xf;
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
ot(" and r0,r8,#0xf ;@ Get trap number\n");
ot(" orr r0,r0,#0x20\n");
ot(" mov r0,r0,asl #2\n");
ot(" bl Exception\n");
ot("\n");
Cycles=38; OpEnd();
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);
if(reg!=7) {
ot(";@ Get An\n");
EaCalc(10, 7, 8, 2, 1);
EaRead(10, 1, 8, 2, 7, 1);
}
ot(" ldr r0,[r7,#0x3c] ;@ Get A7\n");
ot(" sub r0,r0,#4 ;@ A7-=4\n");
ot(" mov r11,r0\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(10,11, 8, 2, 7, 1);
ot(";@ Get offset:\n");
EaCalc(0,0,0x3c,1);
EaRead(0,0,0x3c,1,0);
ot(" add r11,r11,r0 ;@ Add offset to A7\n");
ot(" str r11,[r7,#0x3c]\n");
ot("\n");
Cycles=16;
OpEnd();
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);
ot(";@ Get An\n");
EaCalc(10, 7, 8, 2, 1);
EaRead(10, 0, 8, 2, 7, 1);
ot(" add r11,r0,#4 ;@ A7+=4\n");
ot("\n");
ot(";@ Pop An from stack:\n");
MemHandler(0,2);
ot("\n");
ot(" str r11,[r7,#0x3c] ;@ Save A7\n");
ot("\n");
ot(";@ An = value from stack:\n");
EaWrite(10, 0, 8, 2, 7, 1);
Cycles=12;
OpEnd();
return 0;
}
// --------------------- Opcodes 0x4e70+ ---------------------
int Op4E70(int op)
{
int type=0;
type=op&7; // 01001110 01110ttt, 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); Cycles=20;
SuperCheck(op);
PopSr(1);
ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
PopPc();
SuperChange(op);
CheckInterrupt(op);
OpEnd();
SuperEnd(op);
return 0;
case 5: // rts
OpStart(op); Cycles=16;
ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
PopPc();
OpEnd();
return 0;
case 6: // trapv
OpStart(op); Cycles=4;
ot(" tst r9,#0x10000000\n");
ot(" subne r5,r5,#%i\n",30);
ot(" movne r0,#0x1c ;@ TRAPV exception\n");
ot(" blne Exception\n");
OpEnd();
return 0;
case 7: // rtr
OpStart(op); Cycles=20;
PopSr(0);
ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
PopPc();
OpEnd();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
ot("\n");
EaCalc(0,0x003f,sea,0);
ot(";@ Jump - Get new PC from r0\n");
if (op&0x40)
{
// Jmp - Get new PC from r0
ot(" add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");
ot("\n");
}
else
{
ot(";@ Jsr - Push old PC first\n");
ot(" sub r1,r4,r10 ;@ r1 = Old PC\n");
ot(" add r4,r0,r10 ;@ r4 = Memory Base + New PC\n");
ot(" mov r1,r1,lsl #8\n");
ot(" ldr r0,[r7,#0x3c]\n");
ot(" mov r1,r1,asr #8\n");
ot(";@ Push r1 onto stack\n");
ot(" sub r0,r0,#4 ;@ Predecrement A7\n");
ot(" str r0,[r7,#0x3c] ;@ Save A7\n");
MemHandler(1,2);
ot("\n");
}
#if USE_CHECKPC_CALLBACK
CheckPc();
#endif
Cycles=(op&0x40) ? 4 : 12;
Cycles+=Ea_add_ns((op&0x40) ? g_jmp_cycle_table : g_jsr_cycle_table, sea);
OpEnd();
return 0;
}
// --------------------- Opcodes 0x50c8+ ---------------------
// ARM version of 68000 condition codes:
static char *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);
if (cc>=2)
{
ot(";@ Is the condition true?\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000\n");
ot(";@ If so, don't dbra\n");
ot(" b%s DbraTrue%.4x\n",Cond[cc],op);
ot("\n");
}
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(" cmps r0,#-1\n");
ot(" beq DbraMin1%.4x\n",op);
ot("\n");
ot(";@ Get Branch offset:\n");
ot(" ldrsh r0,[r4]\n");
ot(" add r4,r4,r0 ;@ r4 = New PC\n");
ot("\n");
Cycles=12-2;
OpEnd();
ot(";@ Dn.w is -1:\n");
ot("DbraMin1%.4x%s\n", op, ms?"":":");
ot(" add r4,r4,#2 ;@ Skip branch offset\n");
ot("\n");
Cycles=12+2;
OpEnd();
ot(";@ condition true:\n");
ot("DbraTrue%.4x%s\n", op, ms?"":":");
ot(" add r4,r4,#2 ;@ Skip branch offset\n");
ot("\n");
Cycles=12;
OpEnd();
return 0;
}
// --------------------- Opcodes 0x6000+ ---------------------
// Emit a Branch opcode 0110cccc nn (cccc=condition)
int OpBranch(int op)
{
int size=0,use=0;
int offset=0;
int cc=0;
offset=(char)(op&0xff);
cc=(op>>8)&15;
// Special offsets:
if (offset==0) size=1;
if (offset==-1) size=2;
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);
ot(";@ Get Branch offset:\n");
if (size)
{
EaCalc(0,0,0x3c,size);
EaRead(0,0,0x3c,size,0);
}
// above code messes cycles
Cycles=10; // Assume branch taken
if (size==0) ot(" mov r0,r8,asl #24 ;@ Shift 8-bit signed offset up...\n\n");
if (cc==1) ot(" ldr r10,[r7,#0x60] ;@ Get Memory base\n");
if (cc>=2)
{
ot(";@ Is the condition true?\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000\n");
if (size==0) ot(" mov r0,r0,asr #24 ;@ ...shift down\n\n");
ot(" b%s DontBranch%.4x\n",Cond[cc^1],op);
ot("\n");
}
else
{
if (size==0) ot(" mov r0,r0,asr #24 ;@ ...shift down\n\n");
}
ot(";@ Branch taken - Add on r0 to PC\n");
if (cc==1)
{
ot(";@ Bsr - remember old PC\n");
ot(" sub r1,r4,r10 ;@ r1 = Old PC\n");
ot(" mov r1,r1, lsl #8\n");
ot(" mov r1,r1, asr #8\n");
ot("\n");
if (size) ot(" sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);
ot(" ldr r2,[r7,#0x3c]\n");
ot(" add r4,r4,r0 ;@ r4 = New PC\n");
ot(";@ Push r1 onto stack\n");
ot(" sub r0,r2,#4 ;@ Predecrement A7\n");
ot(" str r0,[r7,#0x3c] ;@ Save A7\n");
MemHandler(1,2);
ot("\n");
Cycles=18; // always 18
}
else
{
if (size) ot(" sub r4,r4,#%d ;@ (Branch is relative to Opcode+2)\n",1<<size);
ot(" add r4,r4,r0 ;@ r4 = New PC\n");
ot("\n");
}
#if USE_CHECKPC_CALLBACK
if (offset==0 || offset==-1)
{
ot(";@ Branch is quite far, so may be a good idea to check Memory Base+pc\n");
CheckPc();
}
#endif
OpEnd();
if (cc>=2)
{
ot("DontBranch%.4x%s\n", op, ms?"":":");
Cycles+=(size==1)? 2 : -2; // Branch not taken
OpEnd();
}
return 0;
}

672
cpu/Cyclone/OpLogic.cpp Normal file
View file

@ -0,0 +1,672 @@
#include "app.h"
// --------------------- Opcodes 0x0100+ ---------------------
// Emit a Btst (Register) opcode 0000nnn1 ttaaaaaa
int OpBtstReg(int op)
{
int use=0;
int type=0,sea=0,tea=0;
int size=0;
type=(op>>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);
use&=~0x0e00; // Use same handler for all registers
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
if(type==1||type==3) {
Cycles=8;
} else {
Cycles=type?8:4;
if(size>=2) Cycles+=2;
}
EaCalc (0,0x0e00,sea,0);
EaRead (0, 0,sea,0,0x0e00);
if (tea>=0x10)
ot(" and r10,r0,#7 ;@ mem - do mod 8\n");
else ot(" and r10,r0,#31 ;@ reg - do mod 32\n");
ot("\n");
EaCalc(11,0x003f,tea,size);
EaRead(11, 0,tea,size,0x003f);
ot(" mov r1,#1\n");
ot(" tst r0,r1,lsl r10 ;@ Do arithmetic\n");
ot(" bicne r9,r9,#0x40000000\n");
ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n");
ot("\n");
if (type>0)
{
if (type==1) ot(" eor r1,r0,r1,lsl r10 ;@ Toggle bit\n");
if (type==2) ot(" bic r1,r0,r1,lsl r10 ;@ Clear bit\n");
if (type==3) ot(" orr r1,r0,r1,lsl r10 ;@ Set bit\n");
ot("\n");
EaWrite(11, 1,tea,size,0x003f);
}
OpEnd();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
ot(" mov r10,#1\n");
ot("\n");
EaCalc ( 0,0x0000,sea,0);
EaRead ( 0, 0,sea,0,0);
ot(" bic r9,r9,#0x40000000 ;@ Blank Z flag\n");
if (tea>=0x10)
ot(" and r0,r0,#7 ;@ mem - do mod 8\n");
else ot(" and r0,r0,#0x1F ;@ reg - do mod 32\n");
ot(" mov r10,r10,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;
}
EaCalc (11,0x003f,tea,size);
EaRead (11, 0,tea,size,0x003f);
ot(" tst r0,r10 ;@ Do arithmetic\n");
ot(" orreq r9,r9,#0x40000000 ;@ Get Z flag\n");
ot("\n");
if (type>0)
{
if (type==1) ot(" eor r1,r0,r10 ;@ Toggle bit\n");
if (type==2) ot(" bic r1,r0,r10 ;@ Clear bit\n");
if (type==3) ot(" orr r1,r0,r10 ;@ Set bit\n");
ot("\n");
EaWrite(11, 1,tea,size,0x003f);
}
OpEnd();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=size<2?4:6;
if(ea >= 0x10) {
Cycles*=2;
#ifdef CYCLONE_FOR_GENESIS
// This is same as in Starscream core, CLR uses only 6 cycles for memory EAs.
// May be this is similar case as with TAS opcode, but this time the dummy
// read is ignored somehow? Without this hack Fatal Rewind hangs even in Gens.
if(type==1&&size<2) Cycles-=2;
#endif
}
EaCalc (10,0x003f,ea,size);
if (type!=1) EaRead (10,0,ea,size,0x003f); // Don't need to read for 'clr'
if (type==1) ot("\n");
if (type==0)
{
ot(";@ Negx:\n");
GetXBit(1);
if(size!=2) ot(" mov r0,r0,lsl #%i\n",size?16:24);
ot(" rscs r1,r0,#0 ;@ do arithmetic\n");
ot(" orr r3,r9,#0xb0000000 ;@ for old Z\n");
OpGetFlags(1,1,0);
if(size!=2) {
ot(" movs r1,r1,asr #%i\n",size?16:24);
ot(" orreq r9,r9,#0x40000000 ;@ possily missed Z\n");
}
ot(" andeq r9,r9,r3 ;@ fix Z\n");
ot("\n");
}
if (type==1)
{
ot(";@ Clear:\n");
ot(" mov r1,#0\n");
ot(" mov r9,#0x40000000 ;@ NZCV=0100\n");
ot("\n");
}
if (type==2)
{
ot(";@ Neg:\n");
if(size!=2) ot(" mov r0,r0,lsl #%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");
ot(" mvn r1,r0\n");
ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
OpGetFlags(0,0);
ot("\n");
}
EaWrite(10, 1,ea,size,0x003f);
OpEnd();
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 (10,0x0007,ea,2,1);
EaRead (10, 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(10, 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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); 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 r9,cpsr ;@ r9=flags\n");
ot("\n");
OpEnd();
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<<size);
use=OpBase(op);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
EaCalc (10,0x0007,ea,size+1);
EaRead (10, 0,ea,size+1,0x0007);
ot(" mov r0,r0,asl #%d\n",shift);
ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
ot(" mrs r9,cpsr ;@ r9=flags\n");
ot(" mov r1,r0,asr #%d\n",shift);
ot("\n");
EaWrite(10, 1,ea,size+1,0x0007);
OpEnd();
return 0;
}
// --------------------- Opcodes 0x50c0+ ---------------------
// Emit a Set cc opcode, 0101cccc 11eeeeee
int OpSet(int op)
{
int cc=0,ea=0;
int size=0,use=0;
char *cond[16]=
{
"al","", "hi","ls","cc","cs","ne","eq",
"vc","vs","pl","mi","ge","lt","gt","le"
};
cc=(op>>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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=8;
if (ea<8) Cycles=4;
ot(" mov r1,#0\n");
if (cc!=1)
{
ot(";@ Is the condition true?\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
ot(" msr cpsr_flg,r9 ;@ ARM flags = 68000 flags\n");
if ((cc&~1)==2) ot(" eor r9,r9,#0x20000000 ;@ Invert carry for hi/ls\n");
ot(" mvn%s r1,r1\n",cond[cc]);
}
if (cc!=1 && ea<8) ot(" sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]);
ot("\n");
EaCalc (0,0x003f, ea,size);
EaWrite(0, 1, ea,size,0x003f);
OpEnd();
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<<size);
if (count>=1) sprintf(pct,"#%d",count); // Fixed count
if (usereg)
{
ot(";@ Use Dn for count:\n");
ot(" and r2,r8,#7<<9\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<<size));
ot("\n");
}
if (type==0 && dir) ot(" mov r3,r0 ;@ save old value for V flag calculation\n");
ot(";@ Shift register:\n");
if (type==0) ot(" movs r0,r0,%s %s\n",dir?"asl":"asr",pct);
if (type==1) ot(" movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);
if (dir==0 && size<2)
{
ot(";@ restore after right shift:\n");
ot(" mov r0,r0,lsl #%d\n",32-(8<<size));
ot("\n");
}
OpGetFlags(0,0);
if (usereg) { // store X only if count is not 0
ot(" cmp %s,#0 ;@ shifting by 0?\n",pct);
ot(" biceq r9,r9,#0x20000000 ;@ if so, clear carry\n");
ot(" movne r1,r9,lsr #28\n");
ot(" strneb r1,[r7,#0x45] ;@ else Save X bit\n");
} else {
// count will never be 0 if we use immediate
ot(" mov r1,r9,lsr #28\n");
ot(" strb r1,[r7,#0x45] ;@ Save X bit\n");
}
if (type==0 && dir) {
ot(";@ calculate V flag (set if sign bit changes at anytime):\n");
ot(" mov r1,#0x80000000\n");
ot(" ands r3,r3,r1,asr %s\n", pct);
ot(" cmpne r3,r1,asr %s\n", pct);
ot(" biceq r9,r9,#0x10000000\n");
ot(" orrne r9,r9,#0x10000000\n");
}
ot("\n");
}
// --------------------------------------
if (type==2)
{
int wide=8<<size;
// Roxr
if(count == 1) {
if(dir==0) {
if(size!=2) {
ot(" orr r0,r0,r0,lsr #%i\n", size?16:24);
ot(" bic r0,r0,#0x%x\n", 1<<(32-wide));
}
GetXBit(0);
ot(" movs r0,r0,rrx\n");
OpGetFlags(0,1);
} else {
ot(" ldrb r3,[r7,#0x45]\n");
ot(" movs r0,r0,lsl #1\n");
OpGetFlags(0,1);
ot(" tst r3,#2\n");
ot(" orrne r0,r0,#0x%x\n", 1<<(32-wide));
ot(" bicne r9,r9,#0x40000000 ;@ clear Z in case it got there\n");
}
ot(" bic r9,r9,#0x10000000 ;@ make suve V is clear\n");
return 0;
}
if (usereg)
{
ot(";@ Reduce r2 until <0:\n");
ot("Reduce_%.4x%s\n",op,ms?"":":");
ot(" subs r2,r2,#%d\n",wide+1);
ot(" bpl Reduce_%.4x\n",op);
ot(" adds r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);
ot(" beq norotx%.4x\n",op);
ot("\n");
}
if (usereg||count < 0)
{
if (dir) ot(" rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);
}
else
{
if (dir) ot(" mov r2,#%d ;@ Reversed\n",wide+1-count);
else ot(" mov r2,#%d\n",count);
}
if (shift) ot(" mov r0,r0,lsr #%d ;@ Shift down\n",shift);
ot(";@ Rotate bits:\n");
ot(" mov r3,r0,lsr r2 ;@ Get right part\n");
ot(" rsbs r2,r2,#%d ;@ should also clear ARM V\n",wide+1);
ot(" movs r0,r0,lsl r2 ;@ Get left part\n");
ot(" orr r0,r3,r0 ;@ r0=Rotated value\n");
ot(";@ Insert X bit into r2-1:\n");
ot(" ldrb r3,[r7,#0x45]\n");
ot(" sub r2,r2,#1\n");
ot(" and r3,r3,#2\n");
ot(" mov r3,r3,lsr #1\n");
ot(" orr r0,r0,r3,lsl r2\n");
ot("\n");
if (shift) ot(" movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);
OpGetFlags(0,!usereg);
if (!shift) {
ot(" tst r0,r0\n");
ot(" bicne r9,r9,#0x40000000 ;@ make sure we didn't mess Z\n");
}
if (usereg) { // store X only if count is not 0
ot(" mov r2,r9,lsr #28\n");
ot(" strb r2,[r7,#0x45] ;@ if not 0, Save X bit\n");
ot(" b nozerox%.4x\n",op);
ot("norotx%.4x%s\n",op,ms?"":":");
ot(" ldrb r2,[r7,#0x45]\n");
ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
OpGetFlags(0,0);
ot(" and r2,r2,#2\n");
ot(" orr r9,r9,r2,lsl #28 ;@ C = old_X\n");
ot("nozerox%.4x%s\n",op,ms?"":":");
}
ot("\n");
}
// --------------------------------------
if (type==3)
{
// Ror
if (size<2)
{
ot(";@ Mirror value in whole 32 bits:\n");
if (size<=0) ot(" orr r0,r0,r0,lsr #8\n");
if (size<=1) ot(" orr r0,r0,r0,lsr #16\n");
ot("\n");
}
ot(";@ Rotate register:\n");
if (count<0)
{
if (dir) ot(" rsbs %s,%s,#32\n",pct,pct);
ot(" movs r0,r0,ror %s\n",pct);
}
else
{
int ror=count;
if (dir) ror=32-ror;
if (ror&31) ot(" movs r0,r0,ror #%d\n",ror);
}
OpGetFlags(0,0);
if (!dir) ot(" bic r9,r9,#0x10000000 ;@ make suve V is clear\n");
if (dir)
{
ot(";@ Get carry bit from bit 0:\n");
if (usereg)
{
ot(" cmp %s,#32 ;@ rotating by 0?\n",pct);
ot(" tstne r0,#1 ;@ no, check bit 0\n");
}
else
ot(" tst r0,#1\n");
ot(" orrne r9,r9,#0x20000000\n");
ot(" biceq r9,r9,#0x20000000\n");
}
else if (usereg)
{
// if we rotate something by 0, ARM doesn't clear C
// so we need to detect that
ot(" cmp %s,#0\n",pct);
ot(" biceq r9,r9,#0x20000000\n");
}
ot("\n");
}
// --------------------------------------
return 0;
}
// Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn
// (ccc=count, d=direction(r,l) xx=size extension, u=use reg for count, tt=type, nnn=register Dn)
int OpAsr(int op)
{
int ea=0,use=0;
int count=0,dir=0;
int size=0,usereg=0,type=0;
ea=0;
count =(op>>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); Cycles=size<2?6:8;
EaCalc(10,0x0007, ea,size,1);
EaRead(10, 0, ea,size,0x0007,1);
EmitAsr(op,type,dir,count, size,usereg);
EaWrite(10, 0, ea,size,0x0007,1);
OpEnd();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=6; // EmitAsr() will add 2
EaCalc (10,0x003f,ea,size,1);
EaRead (10, 0,ea,size,0x003f,1);
EmitAsr(op,type,dir,1,size,0);
EaWrite(10, 0,ea,size,0x003f,1);
OpEnd();
return 0;
}
int OpTas(int op)
{
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
if(ea>=8) Cycles+=10;
EaCalc (10,0x003f,ea,0,1);
EaRead (10, 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) {
#endif
ot(" orr r1,r1,#0x80000000 ;@ set bit7\n");
EaWrite(10, 1,ea,0,0x003f,1);
#if CYCLONE_FOR_GENESIS
}
#endif
OpEnd();
return 0;
}

616
cpu/Cyclone/OpMove.cpp Normal file
View file

@ -0,0 +1,616 @@
#include "app.h"
// Pack our flags into r1, in SR/CCR register format
// trashes r0,r2
void OpFlagsToReg(int high)
{
ot(" ldrb r0,[r7,#0x45] ;@ X bit\n");
ot(" mov r1,r9,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,#0x02\n");
ot(" orr r1,r1,r0,lsl #3 ;@ ___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)
{
ot(" eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");
ot(" mov r2,r0,lsr #3 ;@ r2=___XN\n");
ot(" tst r1,#1 ;@ 1 if C!=V\n");
ot(" eorne r0,r0,#3 ;@ ___XNZCV\n");
ot(" strb r2,[r7,#0x45] ;@ Store X bit\n");
ot(" mov r9,r0,lsl #28 ;@ r9=NZCV...\n");
if (high)
{
ot(" mov r0,r0,ror #8\n");
ot(" and r0,r0,#0xa7 ;@ only take defined bits\n");
ot(" strb r0,[r7,#0x44] ;@ Store SR high\n");
}
ot("\n");
}
// checks for supervisor bit, if not set, jumps to SuperEnd()
// also sets r11 to SR high value, SuperChange() uses this
void SuperCheck(int op)
{
ot(" ldr r11,[r7,#0x44] ;@ Get SR high\n");
ot(" tst r11,#0x20 ;@ Check we are in supervisor mode\n");
ot(" beq WrongMode%.4x ;@ No\n",op);
ot("\n");
}
void SuperEnd(int op)
{
ot("WrongMode%.4x%s\n",op,ms?"":":");
ot(" sub r4,r4,#2 ;@ this opcode wasn't executed - go back\n");
ot(" mov r0,#0x20 ;@ privilege violation\n");
ot(" bl Exception\n");
Cycles=34;
OpEnd();
}
// does OSP and A7 swapping if needed
// new or old SR (not the one already in [r7,#0x44]) should be passed in r11
// trashes r1,r11
void SuperChange(int op)
{
ot(";@ A7 <-> OSP?\n");
ot(" ldr r1,[r7,#0x44] ;@ Get other SR high\n");
ot(" and r11,r11,#0x20\n");
ot(" and r1,r1,#0x20\n");
ot(" teq r11,r1 ;@ r11 xor r1\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 r1, [r7,#0x48] ;@ Get OSP\n");
ot(" str r11,[r7,#0x48]\n");
ot(" str r1, [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);
if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7
if (tea>=0x18 && tea<0x28 && (tea&7)==7) use|=0x0e00; // Specific handler for (a7)+ and -(a7)
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=4;
EaCalc(0,0x003f,sea,size);
EaRead(0, 1,sea,size,0x003f);
if (movea==0) {
ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
ot(" mrs r9,cpsr ;@ r9=NZCV flags\n");
ot("\n");
}
if (movea) size=2; // movea always expands to 32-bits
EaCalc (0,0x0e00,tea,size);
#if SPLIT_MOVEL_PD
if ((tea&0x38)==0x20 && size==2) { // -(An)
ot(" mov r10,r0\n");
ot(" mov r11,r1\n");
ot(" add r0,r0,#2\n");
EaWrite(0, 1,tea,1,0x0e00);
EaWrite(10, 11,tea,1,0x0e00,1);
} else {
EaWrite(0, 1,tea,size,0x0e00);
}
#else
EaWrite(0, 1,tea,size,0x0e00);
#endif
#if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES
// this is a bit hacky
if ((tea==0x39||(tea&0x38)==0x10)&&size>=1)
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
#endif
if((tea&0x38)==0x20) Cycles-=2; // less cycles when dest is -(An)
OpEnd();
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);
use&=~0x0e00; // Also use 1 handler for target ?0-7
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
EaCalc (1,0x003f,sea,0); // Lea
EaCalc (0,0x0e00,tea,2,1);
EaWrite(0, 1,tea,2,0x0e00,1);
Cycles=Ea_add_ns(g_lea_cycle_table,sea);
OpEnd();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
Cycles=12;
if (type==0) Cycles=(ea>=8)?8:6;
if (type==3) SuperCheck(op); // 68000 model allows reading whole SR in user mode (but newer models don't)
if (type==0 || type==1)
{
OpFlagsToReg(type==0);
EaCalc (0,0x003f,ea,size);
EaWrite(0, 1,ea,size,0x003f);
}
if (type==2 || type==3)
{
EaCalc(0,0x003f,ea,size);
EaRead(0, 0,ea,size,0x003f);
OpRegToFlags(type==3);
if (type==3) {
SuperChange(op);
CheckInterrupt(op);
}
}
OpEnd();
if (type==3) SuperEnd(op);
return 0;
}
// Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100
int OpArithSr(int op)
{
int type=0,ea=0;
int use=0,size=0;
type=(op>>9)&5; if (type==4) return 1;
size=(op>>6)&1; // ccr or sr?
ea=0x3c;
use=OpBase(op);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op); Cycles=16;
if (size) SuperCheck(op);
EaCalc(0,0x003f,ea,size);
EaRead(0, 10,ea,size,0x003f);
OpFlagsToReg(size);
if (type==0) ot(" orr r0,r1,r10\n");
if (type==1) ot(" and r0,r1,r10\n");
if (type==5) ot(" eor r0,r1,r10\n");
OpRegToFlags(size);
if (size) {
SuperChange(op);
CheckInterrupt(op);
}
OpEnd();
if (size) SuperEnd(op);
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
ot(" ldr r10,[r7,#0x3c]\n");
EaCalc (1,0x003f, ea,0);
ot("\n");
ot(" sub r0,r10,#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();
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);
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
OpStart(op);
ot(" stmdb sp!,{r9} ;@ Push r9\n"); // can't just use r12 or lr here, because memhandlers touch them
ot(" ldrh r11,[r4],#2 ;@ r11=register mask\n");
ot("\n");
ot(";@ Get the address into r9:\n");
EaCalc(9,0x003f,cea,size);
ot(";@ r10=Register Index*4:\n");
if (decr) ot(" mov r10,#0x3c ;@ order reversed for -(An)\n");
else ot(" mov r10,#0\n");
ot("\n");
ot("MoreReg%.4x%s\n",op, ms?"":":");
ot(" tst r11,#1\n");
ot(" beq SkipReg%.4x\n",op);
ot("\n");
if (decr) ot(" sub r9,r9,#%d ;@ Pre-decrement address\n",1<<size);
if (dir)
{
ot(" ;@ Copy memory to register:\n",1<<size);
EaRead (9,0,ea,size,0x003f);
ot(" str r0,[r7,r10] ;@ Save value into Dn/An\n");
}
else
{
ot(" ;@ Copy register to memory:\n",1<<size);
ot(" ldr r1,[r7,r10] ;@ Load value from Dn/An\n");
EaWrite(9,1,ea,size,0x003f);
}
if (decr==0) ot(" add r9,r9,#%d ;@ Post-increment address\n",1<<size);
ot(" sub r5,r5,#%d ;@ Take some cycles\n",2<<size);
ot("\n");
ot("SkipReg%.4x%s\n",op, ms?"":":");
ot(" movs r11,r11,lsr #1;@ Shift mask:\n");
ot(" add r10,r10,#%d ;@ r10=Next Register\n",decr?-4:4);
ot(" bne MoreReg%.4x\n",op);
ot("\n");
if (change)
{
ot(";@ Write back address:\n");
EaCalc (0,0x0007,8|(ea&7),2);
EaWrite(0, 9,8|(ea&7),2,0x0007);
}
ot(" ldmia sp!,{r9} ;@ Pop r9\n");
ot("\n");
if(dir) { // er
if (ea==0x3a) Cycles=16; // ($nn,PC)
else if (ea==0x3b) Cycles=18; // ($nn,pc,Rn)
else Cycles=12;
} else {
Cycles=8;
}
Cycles+=Ea_add_ns(g_movem_cycle_table,ea);
OpEnd();
return 0;
}
// --------------------- Opcodes 0x4e60+ ---------------------
// Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP
int OpMoveUsp(int op)
{
int use=0,dir=0;
dir=(op>>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); Cycles=4;
SuperCheck(op);
if (dir)
{
ot(" ldr r1,[r7,#0x48] ;@ Get from USP\n\n");
EaCalc (0,0x0007,8,2,1);
EaWrite(0, 1,8,2,0x0007,1);
}
else
{
EaCalc (0,0x0007,8,2,1);
EaRead (0, 0,8,2,0x0007,1);
ot(" str r0,[r7,#0x48] ;@ Put in USP\n\n");
}
OpEnd();
SuperEnd(op);
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 r9,cpsr ;@ r9=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 r10,r8,#0x0e00 ;@ Find T register\n");
ot(" and r11,r8,#0x000f ;@ Find S register\n");
if (type==0x48) ot(" orr r10,r10,#0x1000 ;@ T is an address register\n");
ot("\n");
ot(" ldr r0,[r7,r10,lsr #7] ;@ Get T\n");
ot(" ldr r1,[r7,r11,lsl #2] ;@ Get S\n");
ot("\n");
ot(" str r0,[r7,r11,lsl #2] ;@ T->S\n");
ot(" str r1,[r7,r10,lsr #7] ;@ S->T\n");
ot("\n");
OpEnd();
return 0;
}
// ------------------------- movep -------------------------------
// 0000ddd1 0z001sss
// 0000sss1 1z001ddd (to mem)
int OpMovep(int op)
{
int ea=0;
int size=1,use=0,dir;
use=op&0xf1f8;
if (op!=use) { OpUse(op,use); return 0; } // Use existing handler (for all dests, srcs)
// Get EA
ea = (op&0x0007)|0x28;
dir = (op>>7)&1;
// Find size extension
if(op&0x0040) size=2;
OpStart(op);
if(dir) { // reg to mem
EaCalc(11,0x0e00,0,size); // reg number -> r11
EaRead(11,11,0,size,0x0e00); // regval -> r11
EaCalc(10,0x0007,ea,size);
if(size==2) { // if operand is long
ot(" mov r1,r11,lsr #24 ;@ first byte\n");
EaWrite(10,1,ea,0,0x0007); // store first byte
ot(" add r10,r10,#2\n");
ot(" mov r1,r11,lsr #16 ;@ second byte\n");
EaWrite(10,1,ea,0,0x0007); // store second byte
ot(" add r10,r10,#2\n");
}
ot(" mov r1,r11,lsr #8 ;@ first or third byte\n");
EaWrite(10,1,ea,0,0x0007);
ot(" add r10,r10,#2\n");
ot(" and r1,r11,#0xff\n");
EaWrite(10,1,ea,0,0x0007);
} else { // mem to reg
EaCalc(10,0x0007,ea,size,1);
EaRead(10,11,ea,0,0x0007,1); // read first byte
ot(" add r10,r10,#2\n");
EaRead(10,1,ea,0,0x0007,1); // read second byte
if(size==2) { // if operand is long
ot(" orr r11,r11,r1,lsr #8 ;@ second byte\n");
ot(" add r10,r10,#2\n");
EaRead(10,1,ea,0,0x0007,1);
ot(" orr r11,r11,r1,lsr #16 ;@ third byte\n");
ot(" add r10,r10,#2\n");
EaRead(10,1,ea,0,0x0007,1);
ot(" orr r0,r11,r1,lsr #24 ;@ fourth byte\n");
} else {
ot(" orr r0,r11,r1,lsr #8 ;@ second byte\n");
}
// store the result
EaCalc(11,0x0e00,0,size,1); // reg number -> r11
EaWrite(11,0,0,size,0x0e00,1);
}
Cycles=(size==2)?24:16;
OpEnd();
return 0;
}
// Emit a Stop/Reset opcodes, 01001110 011100t0 imm
int OpStopReset(int op)
{
int type=(op>>1)&1; // reset/stop
OpStart(op);
SuperCheck(op);
if(type) {
// copy immediate to SR, stop the CPU and eat all remaining cycles.
ot(" ldrh r0,[r4],#2 ;@ Fetch the immediate\n");
SuperChange(op);
OpRegToFlags(1);
ot("\n");
ot(" mov r0,#1\n");
ot(" str r0,[r7,#0x58] ;@ stopped\n");
ot("\n");
ot(" mov r5,#0 ;@ eat cycles\n");
Cycles = 4;
ot("\n");
}
else
{
Cycles = 132;
#if USE_RESET_CALLBACK
ot(" str r4,[r7,#0x40] ;@ Save PC\n");
ot(" mov r1,r9,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(" movne pc,r11 ;@ call ResetCallback if it is defined\n");
ot(" ldrb r9,[r7,#0x46] ;@ r9 = Load Flags (NZCV)\n");
ot(" ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
ot(" ldr r4,[r7,#0x40] ;@ Load PC\n");
ot(" mov r9,r9,lsl #28\n");
#endif
}
OpEnd();
SuperEnd(op);
return 0;
}

100
cpu/Cyclone/app.h Normal file
View file

@ -0,0 +1,100 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
// Disa.c
#include "Disa/Disa.h"
// Ea.cpp
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 EaRead(int a,int v,int ea,int size,int mask,int top=0);
int EaCanRead(int ea,int size);
int EaWrite(int a,int v,int ea,int size,int mask,int top=0);
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 char *Narm[4]; // Normal ARM Extensions for operand sizes 0,1,2
extern char *Sarm[4]; // Sign-extend ARM Extensions for operand sizes 0,1,2
extern int Cycles; // Current cycles for opcode
void ot(const char *format, ...);
void ltorg();
void CheckInterrupt(int op);
int MemHandler(int type,int size);
// OpAny.cpp
int OpGetFlags(int subtract,int xbit,int sprecialz=0);
void OpUse(int op,int use);
void OpStart(int op);
void OpEnd();
int OpBase(int op,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);
// OpMove.cpp
int OpMove(int op);
int OpLea(int op);
void OpFlagsToReg(int high);
void OpRegToFlags(int high);
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); // notaz
int OpStopReset(int op);
void SuperCheck(int op);
void SuperEnd(int op);
void SuperChange(int op);

101
cpu/Cyclone/config.h Normal file
View file

@ -0,0 +1,101 @@
/**
* Cyclone 68000 configuration file
**/
/*
* If this option is enabled, Microsoft ARMASM compatible output is generated.
* Otherwise GNU as syntax is used.
*/
#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 enebled.
* This option also alters timing slightly.
*/
#define CYCLONE_FOR_GENESIS 1
/*
* 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
/*
* Cyclone keeps the 4 least significant bits of SR, PC+membase and it's cycle
* count 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.
* Warning: the PC value will not point to start of instruction (it will be middle or
* end), also updating PC is dangerous, as Cyclone may internally increment the PC
* before fetching the next instruction and continue executing at wrong location.
*/
#define MEMHANDLERS_NEED_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 0
/*
* If enabled, Cyclone will call IrqCallback routine from it's context whenever it
* acknowledges an IRQ. IRQ level is not cleared automatically, do this in your
* hadler if needed. PC, flags and cycles are valid in the context and can be read.
* If disabled, it simply clears the IRQ level and continues execution.
*/
#define USE_INT_ACK_CALLBACK 1
/*
* Enable this if you need/change PC, flags or cycles in your IrqCallback function.
*/
#define INT_ACK_NEEDS_STUFF 0
#define INT_ACK_CHANGES_STUFF 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 1
/*
* 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 shuold 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 1
/*
* 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 1
/*
* 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
/*
* When this option is enabled Cyclone will do two word writes instead of one
* long write when handling MOVE.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

Binary file not shown.

View file

@ -0,0 +1,150 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <e32_exe> <nsymbols>\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;
}

View file

@ -0,0 +1,133 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#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 <pe_exe_or_app_before_petran>\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;
}

View file

@ -0,0 +1,42 @@
*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.

View file

@ -0,0 +1,39 @@
CFLAGS = -Wall
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

View file

@ -0,0 +1,60 @@
# Makefile for MS Visual C
CPP=cl.exe
CPP_PROJ=/nologo /ML /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" $(RC_FLAGS) /YX /FD /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) /nologo /ML /W4 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /c ..\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"
-@erase "Cyclone.o"

View file

@ -0,0 +1,146 @@
# 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /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