text: #include "c68000.h"
  #include "driver.h"
  #include "cpuintrf.h"
  #include "cyclone.h"
  #include "memory.h"
  
  
  typedef struct
  {
  	struct Cyclone regs;
  	int pending_interrupts;
  	int (*MAMEIrqCallback)(int int_level);
  } Cyclone_Regs;
  
  static Cyclone_Regs cyclone;
  int cyclone_ICount;
  
  static unsigned int MyCheckPc(unsigned int pc)
  {
    	pc = (pc-cyclone.regs.membase) & 0xffffff; /* Get the real program counter */
  	change_pc24bew(pc);
  	cyclone.regs.membase=(unsigned int)OP_ROM;
    	return cyclone.regs.membase+pc; /* New program counter */
  }
  
  static void update_irq_line(void)
  {
  	if (cyclone.pending_interrupts & 0xff000000)
  	{
  		int level, mask = 0x80000000;
  		for (level = 7; level; level--, mask >>= 1)
  			if (cyclone.pending_interrupts & mask)
  				break;
  		cyclone.regs.irq = level;
  	}
  	else
  	{
  		cyclone.regs.irq = 0;
  	}
  }
  
  static int MyIrqCallback(int irq)
  {
  	cyclone.pending_interrupts &= ~(1 << (24 + irq));
  	if (cyclone.MAMEIrqCallback)
  		cyclone.MAMEIrqCallback(irq);
  	update_irq_line();
  	return CYCLONE_INT_ACK_AUTOVECTOR;
  }
  
  static void cyclone_Cause_Interrupt(int level)
  {
  	if (level >= 1 && level <= 7)
  		cyclone.pending_interrupts |= 1 << (24 + level);
  	update_irq_line();
  }
  
  static void cyclone_Clear_Interrupt (int level)
  {
  	if (level >= 1 && level <= 7)
  		cyclone.pending_interrupts &= ~(1 << (24 + level));
  	update_irq_line();
  }
  
  static data32_t cpu_readmem24bew_dword(offs_t address)
  {
  	data32_t result = cpu_readmem24bew_word(address) << 16;
  	return result | cpu_readmem24bew_word(address + 2);
  }
  
  static void cpu_writemem24bew_dword(offs_t address, data32_t data)
  {
  	cpu_writemem24bew_word(address, data >> 16);
  	cpu_writemem24bew_word(address + 2, data);
  }
  
  void cyclone_init(void)
  {
     	CycloneInit();
  }
  
  void cyclone_reset(void *param)
  {
  	memset(&cyclone, 0,sizeof(Cyclone_Regs));
  	cyclone.regs.checkpc=MyCheckPc;
  	cyclone.regs.read8  = (unsigned int (*)(unsigned int)) cpu_readmem24bew;
  	cyclone.regs.read16 = (unsigned int (*)(unsigned int)) cpu_readmem24bew_word;
  	cyclone.regs.read32 = (unsigned int (*)(unsigned int)) cpu_readmem24bew_dword;
  	cyclone.regs.write8 = (void (*)(unsigned int, unsigned char)) cpu_writemem24bew;
  	cyclone.regs.write16= (void (*)(unsigned int, unsigned short)) cpu_writemem24bew_word;
  	cyclone.regs.write32= (void (*)(unsigned int, unsigned int)) cpu_writemem24bew_dword;
  	cyclone.regs.fetch8  = (unsigned int (*)(unsigned int)) cpu_readmem24bew;
  	cyclone.regs.fetch16 = (unsigned int (*)(unsigned int)) cpu_readmem24bew_word;
  	cyclone.regs.fetch32 = (unsigned int (*)(unsigned int)) cpu_readmem24bew_dword;
  	cyclone.regs.IrqCallback=MyIrqCallback; /* 0 */
    	cyclone.regs.srh=0x27; /* Set supervisor mode */
    	cyclone.regs.a[7]=cyclone.regs.read32(0); /* Get Stack Pointer */
    	cyclone.regs.membase=0;
    	cyclone.regs.pc=cyclone.regs.checkpc(cyclone.regs.read32(4)); /* Get Program Counter */
  	cyclone.regs.state_flags = 0; /* not stopped or tracing */
     	cyclone.pending_interrupts = 0;
  	CycloneReset(&cyclone.regs);
  }
  
  unsigned int cyclone_get_pc(void)
  {
  	return (cyclone.regs.pc - cyclone.regs.membase) & 0xffffff;
  }
  
  void cyclone_set_context(void *src)
  {
  	if (src)
  	{
  		memcpy(&cyclone,src,sizeof(Cyclone_Regs));
  	}
  	update_irq_line();
  }
  
  unsigned cyclone_get_context(void *dst)
  {
  	if (dst)
  	{
  		memcpy(dst,&cyclone,sizeof(Cyclone_Regs));
  	}
  	return sizeof(Cyclone_Regs);
  
  }
  
  int cyclone_execute(int cycles)
  {
  	cyclone.regs.cycles = cycles;
  	cyclone_ICount = cyclone.regs.cycles;
  	CycloneRun(&cyclone.regs);
  	cyclone_ICount = cyclone.regs.cycles;
     	return (cycles - cyclone.regs.cycles);
  }
  
  void cyclone_exit(void)
  {
  }
  
  void cyclone_set_pc(unsigned val)
  {
  	cyclone.regs.pc=MyCheckPc(val);
  }
  unsigned cyclone_get_sp(void)
  {
  	return cyclone.regs.a[7];
  }
  
  void cyclone_set_sp(unsigned val)
  {
  	cyclone.regs.a[7] = val;
  }
  
  enum
  {
  	/* NOTE: M68K_SP fetches the current SP, be it USP, ISP, or MSP */
  	M68K_PC=1, M68K_SP, M68K_ISP, M68K_USP, M68K_MSP, M68K_SR, M68K_VBR,
  	M68K_SFC, M68K_DFC, M68K_CACR, M68K_CAAR, M68K_PREF_ADDR, M68K_PREF_DATA,
  	M68K_D0, M68K_D1, M68K_D2, M68K_D3, M68K_D4, M68K_D5, M68K_D6, M68K_D7,
  	M68K_A0, M68K_A1, M68K_A2, M68K_A3, M68K_A4, M68K_A5, M68K_A6, M68K_A7
  };
  
  unsigned cyclone_get_reg(int regnum)
  {
      switch( regnum )
      {
  		case M68K_PC: return cyclone_get_pc();
  		case M68K_SP: return cyclone_get_sp();
  		case M68K_ISP: return cyclone.regs.osp;
  		case M68K_USP: return cyclone.regs.osp;
  		case M68K_SR: return CycloneGetSr(&cyclone.regs);
  		case M68K_D0: return cyclone.regs.d[0];
  		case M68K_D1: return cyclone.regs.d[1];
  		case M68K_D2: return cyclone.regs.d[2];
  		case M68K_D3: return cyclone.regs.d[3];
  		case M68K_D4: return cyclone.regs.d[4];
  		case M68K_D5: return cyclone.regs.d[5];
  		case M68K_D6: return cyclone.regs.d[6];
  		case M68K_D7: return cyclone.regs.d[7];
  		case M68K_A0: return cyclone.regs.a[0];
  		case M68K_A1: return cyclone.regs.a[1];
  		case M68K_A2: return cyclone.regs.a[2];
  		case M68K_A3: return cyclone.regs.a[3];
  		case M68K_A4: return cyclone.regs.a[4];
  		case M68K_A5: return cyclone.regs.a[5];
  		case M68K_A6: return cyclone.regs.a[6];
  		case M68K_A7: return cyclone.regs.a[7];
  		case REG_PREVIOUSPC: return (cyclone.regs.prev_pc - cyclone.regs.membase - 2) & 0xffffff;
  		default:
  			if( regnum < REG_SP_CONTENTS )
  			{
  				unsigned offset = cyclone_get_sp() + 4 * (REG_SP_CONTENTS - regnum);
  				if( offset < 0xfffffd )
  					return cpu_readmem24bew_dword( offset );
              }
      }
      return 0;
  }
  
  void cyclone_set_reg(int regnum, unsigned val)
  {
      switch( regnum )
      {
  		case M68K_PC: cyclone_set_pc(val); break;
  		case M68K_SP: cyclone_set_sp(val); break;
  		case M68K_ISP: cyclone.regs.osp = val; break;
  		case M68K_USP: cyclone.regs.osp = val; break;
  		case M68K_SR: CycloneSetSr (&cyclone.regs,val); break;
  		case M68K_D0: cyclone.regs.d[0] = val; break;
  		case M68K_D1: cyclone.regs.d[1] = val; break;
  		case M68K_D2: cyclone.regs.d[2] = val; break;
  		case M68K_D3: cyclone.regs.d[3] = val; break;
  		case M68K_D4: cyclone.regs.d[4] = val; break;
  		case M68K_D5: cyclone.regs.d[5] = val; break;
  		case M68K_D6: cyclone.regs.d[6] = val; break;
  		case M68K_D7: cyclone.regs.d[7] = val; break;
  		case M68K_A0: cyclone.regs.a[0] = val; break;
  		case M68K_A1: cyclone.regs.a[1] = val; break;
  		case M68K_A2: cyclone.regs.a[2] = val; break;
  		case M68K_A3: cyclone.regs.a[3] = val; break;
  		case M68K_A4: cyclone.regs.a[4] = val; break;
  		case M68K_A5: cyclone.regs.a[5] = val; break;
  		case M68K_A6: cyclone.regs.a[6] = val; break;
  		case M68K_A7: cyclone.regs.a[7] = val; break;
  		default:
  			if( regnum < REG_SP_CONTENTS )
  			{
  				unsigned offset = cyclone_get_sp() + 4 * (REG_SP_CONTENTS - regnum);
  				if( offset < 0xfffffd )
  					cpu_writemem24bew_word( offset, val );
              }
      }
  }
  
  void cyclone_set_irq_line(int irqline, int state)
  {
  	if (irqline == IRQ_LINE_NMI)
  		irqline = 7;
  	switch(state)
  	{
  		case CLEAR_LINE:
  			cyclone_Clear_Interrupt(irqline);
  			return;
  		case ASSERT_LINE:
  			cyclone_Cause_Interrupt(irqline);
  			return;
  		default:
  			cyclone_Cause_Interrupt(irqline);
  			return;
  	}
  }
  
  void cyclone_set_irq_callback(int (*callback)(int irqline))
  {
  	cyclone.MAMEIrqCallback = callback;
  }
  
  const char *cyclone_info(void *context, int regnum)
  {
  	switch( regnum )
  	{
  		case CPU_INFO_NAME: return "Cyclone 68000";
  		case CPU_INFO_FAMILY: return "Motorola 68K";
  		case CPU_INFO_VERSION: return "v0.0088";
  		case CPU_INFO_FILE: return __FILE__;
  		case CPU_INFO_CREDITS: return "Copyright Copyright 2004-2007 Dave, Reesy and Notaz. All rights reserved";
  	}
  	return "";
  }
  
  unsigned cyclone_dasm(char *buffer, unsigned pc)
  {
  	change_pc24(pc);
  	sprintf(buffer, "$%04X", cpu_readop16(pc) );
  	return 2;
  }
  