/*************************************************************************** mb86233.c Core implementation for the portable Fujitsu MB86233 series DSP emulator. Written by ElSemi MAME version by Ernesto Corvi TODO: - Properly emulate the TGP Tables from the ROM (See GETEXTERNAL) - Many unknown opcodes and addressing modes - Interrupts? ***************************************************************************/ #include "mb86233.h" #include "debugger.h" /*************************************************************************** STRUCTURES & TYPEDEFS ***************************************************************************/ typedef union { INT32 i; UINT32 u; float f; } MB86233_REG; typedef struct { UINT16 pc; MB86233_REG a; MB86233_REG b; MB86233_REG d; MB86233_REG p; UINT16 reps; UINT16 pcs[4]; UINT8 pcsp; UINT32 eb; UINT32 shift; UINT32 repcnt; UINT16 sr; UINT32 gpr[16]; UINT32 extport[0x30]; const device_config *device; const address_space *program; /* FIFO */ int fifo_wait; int (*fifo_read_cb)( UINT32 *data ); void (*fifo_write_cb)( UINT32 data ); /* internal RAM */ UINT32 *RAM; UINT32 *ARAM, *BRAM; UINT32 *Tables; } MB86233_REGS; /*************************************************************************** PRIVATE GLOBAL VARIABLES ***************************************************************************/ static MB86233_REGS mb86233; static int mb86233_icount; /*************************************************************************** MACROS ***************************************************************************/ #define GETPC() mb86233.pc #define GETA() mb86233.a #define GETB() mb86233.b #define GETD() mb86233.d #define GETP() mb86233.p #define GETSR() mb86233.sr #define GETGPR(a) mb86233.gpr[a] #define GETSHIFT() mb86233.shift #define GETPCS() mb86233.pcs #define GETPCSP() mb86233.pcsp #define GETEB() mb86233.eb #define GETREPS() mb86233.reps #define GETEXTPORT() mb86233.extport #define GETFIFOWAIT() mb86233.fifo_wait #define GETARAM() mb86233.ARAM #define GETBRAM() mb86233.BRAM #define ALU(a) mb86233_alu(a) #define GETREPCNT() mb86233.repcnt #define ROPCODE(a) memory_decrypted_read_dword(mb86233.program, a<<2) #define RDMEM(a) memory_read_dword_32le(mb86233.program, (a<<2)) #define WRMEM(a,v) memory_write_dword_32le(mb86233.program, (a<<2), v) /*************************************************************************** Context Switching ***************************************************************************/ static CPU_GET_CONTEXT( mb86233 ) { /* copy the context */ *(MB86233_REGS *)dst = mb86233; } static CPU_SET_CONTEXT( mb86233 ) { /* copy the context */ if (src) mb86233 = *(MB86233_REGS *)src; } /*************************************************************************** Initialization and Shutdown ***************************************************************************/ static CPU_INIT( mb86233 ) { mb86233_cpu_core * _config = (mb86233_cpu_core *)device->static_config; (void)index; (void)clock; (void)irqcallback; memset(&mb86233, 0, sizeof( MB86233_REGS ) ); mb86233.device = device; mb86233.program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); if ( _config ) { mb86233.fifo_read_cb = _config->fifo_read_cb; mb86233.fifo_write_cb = _config->fifo_write_cb; } mb86233.RAM = auto_malloc(2 * 0x200 * sizeof(UINT32)); /* 2x 2KB */ memset( mb86233.RAM, 0, 2 * 0x200 * sizeof(UINT32) ); mb86233.ARAM = &mb86233.RAM[0]; mb86233.BRAM = &mb86233.RAM[0x200]; mb86233.Tables = (UINT32*) memory_region(device->machine, _config->tablergn); state_save_register_global_pointer(mb86233.RAM,2 * 0x200 * sizeof(UINT32)); } static CPU_RESET( mb86233 ) { /* zero registers and flags */ mb86233.pc = 0; mb86233.sr = 0; mb86233.pcsp = 0; mb86233.eb = 0; mb86233.shift = 0; mb86233.fifo_wait = 0; } /*************************************************************************** Status Register ***************************************************************************/ #define ZERO_FLAG (1 << 0) #define SIGN_FLAG (1 << 1) #define EXTERNAL_FLAG (1 << 2) //This seems to be a flag coming from some external circuit?? static void FLAGSF( float v ) { GETSR() = 0; if ( v == 0 ) GETSR() |= ZERO_FLAG; if ( v < 0 ) GETSR() |= SIGN_FLAG; } static void FLAGSI( UINT32 v ) { GETSR() = 0; if ( v == 0 ) GETSR() |= ZERO_FLAG; if ( v & 0x80000000 ) GETSR() |= SIGN_FLAG; } /*************************************************************************** Condition Codes ***************************************************************************/ static int COND( UINT32 cond ) { switch( cond ) { case 0x00: /* eq */ if ( (GETSR() & ZERO_FLAG) ) return 1; break; case 0x01: /* ge */ if ( (GETSR() & ZERO_FLAG) || ((GETSR() & SIGN_FLAG)==0) ) return 1; break; case 0x02: /* le */ if ( (GETSR() & ZERO_FLAG) || (GETSR() & SIGN_FLAG) ) return 1; break; case 0x06: /* never */ break; case 0x0a: if(GETSR() & EXTERNAL_FLAG) return 1; break; case 0x10: /* --r12 != 0 */ GETGPR(12)--; if ( GETGPR(12) != 0 ) return 1; break; case 0x11: /* --r13 != 0 */ GETGPR(13)--; if ( GETGPR(13) != 0 ) return 1; break; case 0x16: /* always */ return 1; break; default: logerror( "TGP: Unknown condition code (cc=%d) at PC:%x\n", cond, GETPC()); break; } return 0; } /*************************************************************************** ALU ***************************************************************************/ static void ALU( UINT32 alu) { float ftmp; switch(alu) { case 0x00: /* NOP */ break; case 0x01: /* D = D & A */ GETD().u &= GETA().u; FLAGSI(GETD().u); break; case 0x02: /* D = D | A */ GETD().u |= GETA().u; FLAGSI(GETD().u); break; case 0x03: /* D = D ^ A */ GETD().u ^= GETA().u; FLAGSI(GETD().u); break; case 0x05: /* CMP D,A */ ftmp = GETD().f - GETA().f; FLAGSF(ftmp); mb86233_icount--; break; case 0x06: /* D = D + A */ GETD().f += GETA().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x07: /* D = D - A */ GETD().f -= GETA().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x08: /* P = A * B */ GETP().f = GETA().f * GETB().f; mb86233_icount--; break; case 0x09: /* D = D + P; P = A * B */ GETD().f += GETP().f; GETP().f = GETA().f * GETB().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x0A: /* D = D - P; P = A * B */ GETD().f -= GETP().f; GETP().f = GETA().f * GETB().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x0B: /* D = fabs(D) */ GETD().f = fabs( GETD().f ); FLAGSF(GETD().f); mb86233_icount--; break; case 0x0C: /* D = D + P */ GETD().f += GETP().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x0D: /* D = P; P = A * B */ GETD().f = GETP().f; GETP().f = GETA().f * GETB().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x0E: /* D = float(D) */ GETD().f = (float)GETD().i; FLAGSF(GETD().f); mb86233_icount--; break; case 0x0F: /* D = int(D) */ GETD().i = (INT32)GETD().f; FLAGSI(GETD().u); break; case 0x10: /* D = D / A */ if ( GETA().u != 0 ) GETD().f = GETD().f / GETA().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x11: /* D = -D */ GETD().f = -GETD().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x13: /* D = A + B */ GETD().f = GETA().f + GETB().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x14: /* D = B - A */ GETD().f = GETB().f - GETA().f; FLAGSF(GETD().f); mb86233_icount--; break; case 0x16: /* LSR D, SHIFT */ GETD().u >>= GETSHIFT(); FLAGSI(GETD().u); break; case 0x17: /* LSL D, SHIFT */ GETD().u <<= GETSHIFT(); FLAGSI(GETD().u); break; case 0x18: /* ASR D, SHIFT */ // GETD().u = (GETD().u & 0x80000000) | (GETD().u >> GETSHIFT()); GETD().i >>= GETSHIFT(); FLAGSI(GETD().u); break; case 0x1A: /* D = D + A */ GETD().i += GETA().i; FLAGSI(GETD().u); break; case 0x1B: /* D = D - A */ GETD().i -= GETA().i; FLAGSI(GETD().u); break; default: logerror( "TGP: Unknown ALU op %x at PC:%04x\n", alu, GETPC() ); break; } } /*************************************************************************** Memory Access ***************************************************************************/ static UINT32 ScaleExp(unsigned int v,int scale) { int exp=(v>>23)&0xff; exp+=scale; v&=~0x7f800000; return v|(exp<<23); } static UINT32 GETEXTERNAL( UINT32 EB, UINT32 offset ) { UINT32 addr; if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */ { if(offset>=0x20 && offset<=0x23) //SIN from value at RAM(0x20) in 0x4000/PI steps { UINT32 r; UINT32 value=GETEXTPORT()[0x20]; UINT32 off; value+=(offset-0x20)<<14; off=value&0x3fff; if((value&0x7fff)==0) r=0; else if((value&0x7fff)==0x4000) r=0x3f800000; else { if(value&0x4000) off=0x4000-off; r=mb86233.Tables[off]; } if(value&0x8000) r|=1<<31; return r; } if(offset==0x27) { unsigned int value=GETEXTPORT()[0x27]; int exp=(value>>23)&0xff; unsigned int res=0; unsigned int sign=0; MB86233_REG a,b; int index; a.u=GETEXTPORT()[0x24]; b.u=GETEXTPORT()[0x25]; if(!exp) { if((a.u&0x7fffffff)<=(b.u&0x7fffffff)) { if(b.u&0x80000000) res=0xc000; else res=0x4000; } else { if(a.u&0x80000000) res=0x8000; else res=0x0000; } return res; } if((a.u^b.u)&0x80000000) sign=16; //the negative values are in the high word if((exp&0x70)!=0x70) index=0; else if(exp<0x70 || exp>0x7e) index=0x3fff; else { int expdif=exp-0x71; int base; int mask; int shift; if(expdif<0) expdif=0; base=1<>shift)&mask); } res=(mb86233.Tables[index+0x10000/4]>>sign)&0xffff; if((a.u&0x7fffffff)<=(b.u&0x7fffffff)) res=0x4000-res; if((a.u&0x80000000) && (b.u&0x80000000)) //3rd quadrant { res=0x8000|res; } else if((a.u&0x80000000) && !(b.u&0x80000000)) //2nd quadrant { res=res&0x7fff; } else if(!(a.u&0x80000000) && (b.u&0x80000000)) //2nd quadrant { res=0x8000|res; } return res; } if(offset==0x28) { UINT32 offset=(GETEXTPORT()[0x28]>>10)&0x1fff; UINT32 value=mb86233.Tables[offset*2+0x20000/4]; UINT32 srcexp=(GETEXTPORT()[0x28]>>23)&0xff; value&=0x7FFFFFFF; return ScaleExp(value,0x7f-srcexp); } if(offset==0x29) { UINT32 offset=(GETEXTPORT()[0x28]>>10)&0x1fff; UINT32 value=mb86233.Tables[offset*2+(0x20000/4)+1]; UINT32 srcexp=(GETEXTPORT()[0x28]>>23)&0xff; value&=0x7FFFFFFF; if(GETEXTPORT()[0x28]&(1<<31)) value|=1<<31; return ScaleExp(value,0x7f-srcexp); } if(offset==0x2a) { UINT32 offset=((GETEXTPORT()[0x2a]>>11)&0x1fff)^0x1000; UINT32 value=mb86233.Tables[offset*2+0x30000/4]; UINT32 srcexp=(GETEXTPORT()[0x2a]>>24)&0x7f; value&=0x7FFFFFFF; return ScaleExp(value,0x3f-srcexp); } if(offset==0x2b) { UINT32 offset=((GETEXTPORT()[0x2a]>>11)&0x1fff)^0x1000; UINT32 value=mb86233.Tables[offset*2+(0x30000/4)+1]; UINT32 srcexp=(GETEXTPORT()[0x2a]>>24)&0x7f; value&=0x7FFFFFFF; if(GETEXTPORT()[0x2a]&(1<<31)) value|=1<<31; return ScaleExp(value,0x3f-srcexp); } return GETEXTPORT()[offset]; } addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF ); return RDMEM(addr); } static void SETEXTERNAL( UINT32 EB, UINT32 offset, UINT32 value ) { UINT32 addr; if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */ { GETEXTPORT()[offset] = value; if(offset==0x25 || offset==0x24) { if((GETEXTPORT()[0x24]&0x7fffffff)<=(GETEXTPORT()[0x25]&0x7fffffff)) { GETSR()|=EXTERNAL_FLAG; } else { GETSR()&=~EXTERNAL_FLAG; } } return; } addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF ); WRMEM( addr, value ); } /*************************************************************************** Register Access ***************************************************************************/ static UINT32 GETREGS( UINT32 reg, int source ) { UINT32 mode = ( reg >> 6 ) & 0x07; reg &= 0x3f; if ( mode == 0 || mode == 1 || mode == 3 ) { if ( reg < 0x10 ) { return GETGPR(reg); } switch( reg ) { case 0x10: /* A */ return GETA().u; break; case 0x11: /* A.e */ return (GETA().u >> 23) & 0xff; break; case 0x12: /* A.m */ return (GETA().u & 0x7fffff) | ((GETA().u&0x80000000) >> 8); break; case 0x13: /* B */ return GETB().u; break; case 0x14: /* B.e */ return (GETB().u >> 23) & 0xff; break; case 0x15: /* B.m */ return (GETB().u & 0x7fffff) | ((GETB().u&0x80000000) >> 8); break; case 0x19: /* D */ return GETD().u; break; case 0x1A: /* D.e */ return (GETD().u >> 23) & 0xff; break; case 0x1B: /* D.m */ return (GETD().u & 0x7fffff) | ((GETD().u&0x80000000) >> 8); break; case 0x1C: /* P */ return GETP().u; break; case 0x1D: /* P.e */ return (GETP().u >> 23) & 0xff; break; case 0x1E: /* P.m */ return (GETP().u & 0x7fffff) | ((GETP().u&0x80000000) >> 8); break; case 0x1F: /* Shift */ return GETSHIFT(); break; case 0x20: /* Parallel Port */ logerror( "TGP: Parallel port read at PC:%04x\n", GETPC() ); return 0; break; case 0x21: /* FIn */ { UINT32 fifo_data; if ( mb86233.fifo_read_cb ) { if ( mb86233.fifo_read_cb(&fifo_data) ) { return fifo_data; } } GETFIFOWAIT() = 1; return 0; } break; case 0x22: /* FOut */ return 0; break; case 0x23: /* EB */ return GETEB(); break; case 0x34: return GETREPCNT(); break; default: logerror( "TGP: Unknown GETREG (%d) at PC=%04x\n", reg, GETPC() ); break; } } else if ( mode == 2 ) /* Indexed */ { UINT32 addr = reg & 0x1f; if ( source ) { if( !( reg & 0x20 ) ) addr += GETGPR(0); addr += GETGPR(2); } else { if( !( reg & 0x20 ) ) addr += GETGPR(1); addr += GETGPR(3); } return addr; } else if( mode == 6 ) /* Indexed with postop */ { UINT32 addr = 0; if ( source ) { if( !( reg & 0x20 ) ) addr += GETGPR(0); addr += GETGPR(2); } else { if( !( reg & 0x20 ) ) addr += GETGPR(1); addr += GETGPR(3); } if ( reg & 0x10 ) { if ( source ) GETGPR(2) -= 0x20 - ( reg & 0x1f ); else GETGPR(3) -= 0x20 - ( reg & 0x1f ); } else { if ( source ) GETGPR(2) += ( reg & 0x1f ); else GETGPR(3) += ( reg & 0x1f ); } return addr; } else { fatalerror( "TGP: Unknown GETREG mode %d at PC:%04x\n", mode, GETPC() ); } return 0; } static void SETREGS( UINT32 reg, UINT32 val ) { int mode = ( reg >> 6) & 0x07; reg &= 0x3f; if( mode == 0 || mode == 1 || mode == 3 ) { if ( reg < 0x10 ) { if ( reg == 12 || reg == 13 ) val &= 0xff; GETGPR(reg) = val; return; } switch( reg ) { case 0x10: /* A */ GETA().u = val; break; case 0x11: /* A.e */ GETA().u &= ~((0x0000007f) << 23); GETA().u |= (( val & 0xff ) << 23 ); break; case 0x12: /* A.m */ GETA().u &= ~( 0x807fffff ); GETA().u |= ( val & 0x7fffff ); GETA().u |= ( val & 0x800000 ) << 8; break; case 0x13: /* B */ GETB().u = val; break; case 0x14: /* B.e */ GETB().u &= ~((0x0000007f) << 23); GETB().u |= (( val & 0xff ) << 23 ); break; case 0x15: /* B.m */ GETB().u &= ~( 0x807fffff ); GETB().u |= ( val & 0x7fffff ); GETB().u |= ( val & 0x800000 ) << 8; break; case 0x19: /* D */ GETD().u = val; break; case 0x1A: /* D.e */ GETD().u &= ~((0x0000007f) << 23); GETD().u |= (( val & 0xff ) << 23 ); break; case 0x1B: /* B.m */ GETD().u &= ~( 0x807fffff ); GETD().u |= ( val & 0x7fffff ); GETD().u |= ( val & 0x800000 ) << 8; break; case 0x1C: /* P */ GETP().u = val; break; case 0x1D: /* P.e */ GETP().u &= ~((0x0000007f) << 23); GETP().u |= (( val & 0xff ) << 23 ); break; case 0x1E: /* P.m */ GETP().u &= ~( 0x807fffff ); GETP().u |= ( val & 0x7fffff ); GETP().u |= ( val & 0x800000 ) << 8; break; case 0x1F: GETSHIFT() = val; break; case 0x20: /* Parallel Port */ logerror( "TGP: Parallel port write: %08x at PC:%04x\n", val, GETPC() ); break; case 0x22: /* FOut */ if ( mb86233.fifo_write_cb ) { mb86233.fifo_write_cb( val ); } break; case 0x23: GETEB() = val; break; case 0x34: GETREPCNT() = val; break; default: { fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC()); } break; } } else { fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC()); } } /*************************************************************************** Addressing Modes ***************************************************************************/ static UINT32 INDIRECT( UINT32 reg, int source ) { UINT32 mode = ( reg >> 6 ) & 0x07; if ( mode == 0 || mode == 1 || mode == 3 ) { return reg; } else if ( mode == 2 ) { UINT32 addr = reg & 0x1f; if ( source ) { if( !(reg & 0x20) ) addr += GETGPR(0); addr += GETGPR(2); } else { if( !(reg & 0x20) ) addr += GETGPR(1); addr += GETGPR(3); } return addr; } else if ( mode == 6 || mode == 7 ) { UINT32 addr = 0; if ( source ) { if ( !( reg & 0x20 ) ) addr += GETGPR(0); addr += GETGPR(2); } else { if ( !( reg & 0x20 ) ) addr += GETGPR(1); addr += GETGPR(3); } if ( reg & 0x10 ) { if ( source ) GETGPR(2) -= 0x20 - ( reg & 0x1f ); else GETGPR(3) -= 0x20 - ( reg & 0x1f ); } else { if ( source ) GETGPR(2) += ( reg & 0x1f ); else GETGPR(3) += ( reg & 0x1f ); } return addr; } else { fatalerror( "TGP: Unknown INDIRECT mode %d at PC:%04x\n", mode, GETPC() ); } return 0; } /*************************************************************************** Core Execution Loop ***************************************************************************/ static CPU_EXECUTE( mb86233 ) { mb86233_icount = cycles; while( mb86233_icount > 0 ) { UINT32 val; UINT32 opcode; debugger_instruction_hook(device, GETPC()); opcode = ROPCODE(GETPC()); GETFIFOWAIT() = 0; switch( (opcode >> 26) & 0x3f ) { case 0x00: /* dual move */ { UINT32 r1 = opcode & 0x1ff; UINT32 r2 = ( opcode >> 9 ) & 0x7f; UINT32 alu = ( opcode >> 21 ) & 0x1f; UINT32 op = ( opcode >> 16 ) & 0x1f; ALU( alu ); switch( op ) { case 0x0C: GETA().u = GETARAM()[r1]; GETB().u = GETBRAM()[r2]; break; case 0x0D: GETA().u = GETARAM()[INDIRECT(r1,0)]; GETB().u = GETBRAM()[INDIRECT(r2|2<<6,0)]; break; case 0x0F: GETA().u = GETARAM()[r1]; GETB().u = GETBRAM()[INDIRECT(r2|6<<6,0)]; break; case 0x10: GETA().u = GETBRAM()[INDIRECT(r1,1)]; GETB().u = GETARAM()[r2]; break; case 0x11: GETA().u = GETARAM()[INDIRECT(r1,1)]; GETB().u = GETBRAM()[INDIRECT(r2|(2<<6),0)]; break; default: logerror( "TGP: Unknown TGP double move (op=%d) at PC:%x\n", op, GETPC()); break; } } break; case 0x7: /* LD/MOV */ { UINT32 r1 = opcode & 0x1ff; UINT32 r2 = ( opcode >> 9 ) & 0x7f; UINT32 alu = ( opcode >> 21 ) & 0x1f; UINT32 op = ( opcode >> 16 ) & 0x1f; switch( op ) { case 0x04: /* MOV RAM->External */ { SETEXTERNAL(GETEB(), r2, GETARAM()[r1]); ALU(alu); } break; case 0x0c: /* MOV RAM->BRAM */ { GETBRAM()[r2] = GETARAM()[r1]; ALU(alu); } break; case 0x1d: /* MOV RAM->Reg */ { if ( r1 & 0x180 ) { val = GETARAM()[GETREGS(r1,0)]; } else { val = GETARAM()[r1]; } /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; ALU(alu); SETREGS(r2,val); } break; case 0x1c: /* MOV Reg->RAMInd */ { val = GETREGS(r2,1); /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; ALU(alu); if ( ( r2 >> 6 ) & 0x01) { SETEXTERNAL(GETEB(),INDIRECT(r1,0),val); } else { GETARAM()[INDIRECT(r1,0)] = val; } } break; case 0x1f: /* MOV Reg->Reg */ { if ( r1 == 0x10 && r2 == 0xf ) { /* NOP */ ALU(alu); } else { val = GETREGS(r1,1); /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; ALU(alu); SETREGS( r2, val ); } } break; case 0x0f: /* MOV RAMInd->BRAMInd */ { val = GETARAM()[INDIRECT(r1,1)]; ALU(alu); GETBRAM()[INDIRECT(r2|(6<<6),0)] = val; } break; case 0x13: /* MOV BRAMInd->RAMInd */ { val = GETBRAM()[INDIRECT(r1,1)]; ALU(alu); GETARAM()[INDIRECT(r2|(6<<6),0)] = val; } break; case 0x10: /* MOV RAMInd->RAM */ { val = GETBRAM()[INDIRECT(r1,1)]; ALU(alu); GETARAM()[r2] = val; } break; case 0x1e: /* External->Reg */ { UINT32 offset; if ( ( r2 >> 6 ) & 1 ) offset = INDIRECT(r1,1); else offset = INDIRECT(r1,0); val = GETEXTERNAL(GETEB(),offset); ALU(alu); SETREGS(r2,val); } break; case 0x03: /* RAM->External Ind */ { val = GETARAM()[r1]; ALU(alu); SETEXTERNAL(GETEB(),INDIRECT(r2|(6<<6),0),val); } break; case 0x07: /* RAMInd->External */ { val = GETARAM()[INDIRECT(r1,1)]; ALU(alu); SETEXTERNAL(GETEB(),INDIRECT(r2|(6<<6),0),val); } break; case 0x08: /* External->RAM */ { val = GETEXTERNAL(GETEB(),INDIRECT(r1,1)); ALU(alu); GETARAM()[r2] = val; } break; case 0x0b: /* External->RAMInd */ { val = GETEXTERNAL(GETEB(),INDIRECT(r1,1)); ALU(alu); GETARAM()[INDIRECT(r2|(6<<6),0)] = val; } break; default: logerror( "TGP: Unknown TGP move (op=%d) at PC:%x\n", op, GETPC()); break; } } break; case 0x0e: /* LDIMM24 */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; /* sign extend 24->32 */ if ( imm & 0x800000 ) imm |= 0xFF000000; switch( sub ) { case 0x00: /* P */ GETP().u = imm; break; case 0x01: /* A */ GETA().u = imm; break; case 0x02: /* B */ GETB().u = imm; break; case 0x03: /* D */ GETD().u = imm; break; } } break; case 0x0f: /* REP/CLEAR/FLAGS */ { UINT32 alu = ( opcode >> 20 ) & 0x1f; UINT32 sub2 = ( opcode >> 16 ) & 0x0f; ALU( alu ); if( sub2 == 0x00 ) /* CLEAR reg */ { UINT32 reg = opcode & 0x1f; switch( reg ) { case 0x10: GETD().u = 0; break; case 0x08: GETB().u = 0; break; case 0x04: GETA().u = 0; break; } } else if ( sub2 == 0x04 ) /* REP xxx */ { UINT32 sub3 = ( opcode >> 12 ) & 0x0f; if ( sub3 == 0 ) { GETREPS() = opcode & 0xfff; if ( GETREPS() == 0 ) GETREPS() = 0x100; GETPC()++; } else if ( sub3 == 8 ) { GETREPS() = GETREGS( opcode & 0xfff, 0 ); GETPC()++; } } else if ( sub2 == 0x02 ) /* CLRFLAGS */ { GETSR() &= ~(opcode&0xfff); } else if ( sub2 == 0x06 ) /* SETFLAGS */ { GETSR() |= (opcode&0xfff); } } break; case 0x10: /* LDIMM rx */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffff; GETGPR(sub) = imm; } break; case 0x13: /* LDIMM r1x */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 0 ) /* R12 */ GETGPR(12) = imm & 0xff; else if ( sub == 1 ) /* R13 */ GETGPR(13) = imm & 0xff; else logerror( "TGP: Unknown LDIMM r12 (sub=%d) at PC:%04x\n", sub, GETPC() ); } break; case 0x14: /* LDIMM m,e */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 0 ) /* A */ { GETA().u = imm; } else if ( sub == 1 ) /* A.e */ { GETA().u &= ~0x7f800000; GETA().u |= (imm & 0xff) << 23; } else if ( sub == 2 ) /* A.m */ { GETA().u &= 0x7f800000; GETA().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); } else { logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x15: /* LDIMM m,e */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 0 ) /* B.e again? */ { //GETB().u = ((imm & 0x7f) << 23) | ((imm & 0xff) << 8) | ( imm & 0xff ); GETB().u &= ~0x7f800000; GETB().u |= (imm & 0xff) << 23; } else if ( sub == 1 ) /* B.e */ { GETB().u &= ~0x7f800000; GETB().u |= (imm & 0xff) << 23; } else if ( sub == 2 ) /* B.m */ { GETB().u &= 0x7f800000; GETB().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); } else { logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x16: /* LDIMM m,e */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 1 ) /* clear + D.m */ { GETD().u = (imm & 0x7fffff ) | ((imm & 0x800000) << 8); } else if ( sub == 2 ) /* D.e */ { GETD().u &= ~0x7f800000; GETD().u |= (imm & 0xff) << 23; } else if ( sub == 3 ) /* D.m */ { GETD().u &= 0x7f800000; GETD().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); } else { logerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x17: /* LDIMM special reg */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 0x03 ) { GETSHIFT() = imm; } else { logerror( "TGP: Unknown LDIMM special reg (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x18: /* LDIMM external reg */ { UINT32 sub = (opcode>>24) & 0x03; UINT32 imm = opcode & 0xffffff; if ( sub == 0x03 ) { GETEB() = imm; } else { logerror( "TGP: Unknown LDIMM external reg (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x1d: //LDIMM to Rep regs { UINT32 sub = (opcode>>24)&0x3; UINT32 imm = opcode&0xffffff; if(sub == 0x00) { GETREPCNT() = imm; } else { logerror( "TGP: Unknown LDIMM REPCnt (sub=%d) at PC:%04x\n", sub, GETPC() ); } } break; case 0x2f: /* Conditional Branches */ { UINT32 cond = ( opcode >> 20 ) & 0x1f; UINT32 subtype = ( opcode >> 16 ) & 0x0f; UINT32 data = opcode & 0xffff; if( COND(cond) ) { switch( subtype ) { case 0x00: /* BRIF */ GETPC() = data - 1; break; case 0x02: /* BRIF indirect */ if ( data & 0x4000 ) data = GETREGS(data&0x3f,0) - 1; else data = ((GETARAM()[data&0x3ff])&0xffff)-1; /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; GETPC() = data; break; case 0x04: /* BSIF */ GETPCS()[GETPCSP()] = GETPC(); GETPCSP()++; GETPC() = data - 1; break; case 0x06: /* BSIF indirect */ GETPCS()[GETPCSP()] = GETPC(); GETPCSP()++; if ( data & 0x4000 ) data = GETREGS(data&0x3f,0) - 1; else data = ((GETARAM()[data&0x3ff])&0xffff)-1; /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; GETPC() = data; break; case 0x0a: /* RTIF */ --GETPCSP(); GETPC() = GETPCS()[GETPCSP()]; break; case 0x0c: /* LDIF */ SETREGS(((data>>9)&0x3f), GETARAM()[data&0x1FF] ); break; case 0x0e: /* RIIF */ logerror( "TGP: RIIF unimplemented at PC:%04x\n", GETPC() ); break; default: logerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() ); break; } } } break; case 0x3f: /* Inverse Conditional Branches */ { UINT32 cond = ( opcode >> 20 ) & 0x1f; UINT32 subtype = ( opcode >> 16 ) & 0x0f; UINT32 data = opcode & 0xffff; if( !COND(cond) ) { switch( subtype ) { case 0x00: /* BRUL */ GETPC() = data - 1; break; case 0x02: /* BRUL indirect */ if ( data & 0x4000 ) data = GETREGS(data&0x3f,0) - 1; else data = ((GETARAM()[data&0x3ff])&0xffff)-1; /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; GETPC() = data; break; case 0x04: /* BSUL */ GETPCS()[GETPCSP()] = GETPC(); GETPCSP()++; GETPC() = data - 1; break; case 0x06: /* BSUL indirect */ GETPCS()[GETPCSP()] = GETPC(); GETPCSP()++; if ( data & 0x4000 ) data = GETREGS(data&0x3f,0) - 1; else data = ((GETARAM()[data&0x3ff])&0xffff)-1; /* if we're waiting for data, don't complete the instruction */ if ( GETFIFOWAIT() ) break; GETPC() = data; break; case 0x0a: /* RTUL */ --GETPCSP(); GETPC() = GETPCS()[GETPCSP()]; break; case 0x0c: /* LDUL */ SETREGS(((data>>9)&0x3f), GETARAM()[data&0x1FF] ); break; case 0x0e: /* RIUL */ logerror( "TGP: RIIF unimplemented at PC:%04x\n", GETPC() ); break; default: logerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() ); break; } } } break; default: logerror( "TGP: unknown opcode %08x at PC:%04x\n", opcode, GETPC() ); break; } if ( GETFIFOWAIT() == 0 ) { if( GETREPS() == 0 ) GETPC()++; else --GETREPS(); mb86233_icount--; } else { mb86233_icount = 0; } } return cycles - mb86233_icount; } /*************************************************************************** DISASSEMBLY HOOK ***************************************************************************/ static CPU_DISASSEMBLE( mb86233 ) { extern UINT32 dasm_mb86233(char *, UINT32); UINT32 op = *(UINT32 *)oprom; op = LITTLE_ENDIANIZE_INT32(op); return dasm_mb86233(buffer, op); } /*************************************************************************** Information Setters ***************************************************************************/ static CPU_SET_INFO( mb86233 ) { switch (state) { case CPUINFO_INT_PC: case CPUINFO_INT_REGISTER + MB86233_PC: GETPC() = info->i; break; case CPUINFO_INT_REGISTER + MB86233_A: GETA().u = info->i; break; case CPUINFO_INT_REGISTER + MB86233_B: GETB().u = info->i; break; case CPUINFO_INT_REGISTER + MB86233_P: GETP().u = info->i; break; case CPUINFO_INT_REGISTER + MB86233_D: GETD().u = info->i; break; case CPUINFO_INT_REGISTER + MB86233_REP: GETREPS() = info->i; break; case CPUINFO_INT_SP: case CPUINFO_INT_REGISTER + MB86233_SP: GETPCSP() = info->i; break; case CPUINFO_INT_REGISTER + MB86233_EB: GETEB() = info->i; break; case CPUINFO_INT_REGISTER + MB86233_SHIFT: GETSHIFT() = info->i; break; case CPUINFO_INT_REGISTER + MB86233_FLAGS: GETSR() = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R0: GETGPR(0) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R1: GETGPR(1) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R2: GETGPR(2) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R3: GETGPR(3) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R4: GETGPR(4) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R5: GETGPR(5) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R6: GETGPR(6) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R7: GETGPR(7) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R8: GETGPR(8) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R9: GETGPR(9) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R10: GETGPR(10) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R11: GETGPR(11) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R12: GETGPR(12) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R13: GETGPR(13) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R14: GETGPR(14) = info->i; break; case CPUINFO_INT_REGISTER + MB86233_R15: GETGPR(15) = info->i; break; } } /*************************************************************************** Information Getters ***************************************************************************/ CPU_GET_INFO( mb86233 ) { switch (state) { /* --- the following bits of info are returned as 64-bit signed integers --- */ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(MB86233_REGS); break; case CPUINFO_INT_INPUT_LINES: info->i = 0; break; case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; case CPUINFO_INT_MAX_CYCLES: info->i = 2; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 32; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; case CPUINFO_INT_PC: case CPUINFO_INT_REGISTER + MB86233_PC: info->i = GETPC(); break; case CPUINFO_INT_REGISTER + MB86233_A: info->i = GETA().u; break; case CPUINFO_INT_REGISTER + MB86233_B: info->i = GETB().u; break; case CPUINFO_INT_REGISTER + MB86233_P: info->i = GETP().u; break; case CPUINFO_INT_REGISTER + MB86233_D: info->i = GETD().u; break; case CPUINFO_INT_REGISTER + MB86233_REP: info->i = GETREPS(); break; case CPUINFO_INT_SP: case CPUINFO_INT_REGISTER + MB86233_SP: info->i = GETPCSP(); break; case CPUINFO_INT_REGISTER + MB86233_EB: info->i = GETEB(); break; case CPUINFO_INT_REGISTER + MB86233_SHIFT: info->i = GETSHIFT(); break; case CPUINFO_INT_REGISTER + MB86233_FLAGS: info->i = GETSR(); break; case CPUINFO_INT_REGISTER + MB86233_R0: info->i = GETGPR(0); break; case CPUINFO_INT_REGISTER + MB86233_R1: info->i = GETGPR(1); break; case CPUINFO_INT_REGISTER + MB86233_R2: info->i = GETGPR(2); break; case CPUINFO_INT_REGISTER + MB86233_R3: info->i = GETGPR(3); break; case CPUINFO_INT_REGISTER + MB86233_R4: info->i = GETGPR(4); break; case CPUINFO_INT_REGISTER + MB86233_R5: info->i = GETGPR(5); break; case CPUINFO_INT_REGISTER + MB86233_R6: info->i = GETGPR(6); break; case CPUINFO_INT_REGISTER + MB86233_R7: info->i = GETGPR(7); break; case CPUINFO_INT_REGISTER + MB86233_R8: info->i = GETGPR(8); break; case CPUINFO_INT_REGISTER + MB86233_R9: info->i = GETGPR(9); break; case CPUINFO_INT_REGISTER + MB86233_R10: info->i = GETGPR(10); break; case CPUINFO_INT_REGISTER + MB86233_R11: info->i = GETGPR(11); break; case CPUINFO_INT_REGISTER + MB86233_R12: info->i = GETGPR(12); break; case CPUINFO_INT_REGISTER + MB86233_R13: info->i = GETGPR(13); break; case CPUINFO_INT_REGISTER + MB86233_R14: info->i = GETGPR(14); break; case CPUINFO_INT_REGISTER + MB86233_R15: info->i = GETGPR(15); break; /* --- the following bits of info are returned as pointers to data or functions --- */ case CPUINFO_PTR_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(mb86233); break; case CPUINFO_PTR_GET_CONTEXT: info->getcontext = CPU_GET_CONTEXT_NAME(mb86233); break; case CPUINFO_PTR_SET_CONTEXT: info->setcontext = CPU_SET_CONTEXT_NAME(mb86233); break; case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(mb86233); break; case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(mb86233); break; case CPUINFO_PTR_EXIT: info->exit = NULL; break; case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(mb86233); break; case CPUINFO_PTR_BURN: info->burn = NULL; break; case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(mb86233); break; case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &mb86233_icount; break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case CPUINFO_STR_NAME: strcpy(info->s, "MB86233"); break; case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Fujitsu MB86233"); break; case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break; case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Miguel Angel Horna and Ernesto Corvi"); break; case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c", (GETSR()&SIGN_FLAG) ? 'N' : 'n', (GETSR()&ZERO_FLAG) ? 'Z' : 'z' ); break; case CPUINFO_STR_REGISTER + MB86233_FLAGS: sprintf(info->s, "FL:%c%c", (GETSR()&SIGN_FLAG) ? 'N' : 'n', (GETSR()&ZERO_FLAG) ? 'Z' : 'z' ); break; case CPUINFO_STR_REGISTER + MB86233_PC: sprintf(info->s, "PC:%04X", GETPC()); break; case CPUINFO_STR_REGISTER + MB86233_A: sprintf(info->s, "PA:%08X (%f)", GETA().u, GETA().f); break; case CPUINFO_STR_REGISTER + MB86233_B: sprintf(info->s, "PB:%08X (%f)", GETB().u, GETB().f); break; case CPUINFO_STR_REGISTER + MB86233_P: sprintf(info->s, "PP:%08X (%f)", GETP().u, GETP().f); break; case CPUINFO_STR_REGISTER + MB86233_D: sprintf(info->s, "PD:%08X (%f)", GETD().u, GETD().f); break; case CPUINFO_STR_REGISTER + MB86233_REP: sprintf(info->s, "REPS:%08X", GETREPS()); break; case CPUINFO_STR_REGISTER + MB86233_SP: sprintf(info->s, "PCSP:%1X", GETPCSP()); break; case CPUINFO_STR_REGISTER + MB86233_EB: sprintf(info->s, "EB:%08X", GETEB()); break; case CPUINFO_STR_REGISTER + MB86233_SHIFT: sprintf(info->s, "SHIFT:%08X", GETSHIFT()); break; case CPUINFO_STR_REGISTER + MB86233_R0: sprintf(info->s, "R0:%08X", GETGPR(0)); break; case CPUINFO_STR_REGISTER + MB86233_R1: sprintf(info->s, "R1:%08X", GETGPR(1)); break; case CPUINFO_STR_REGISTER + MB86233_R2: sprintf(info->s, "R2:%08X", GETGPR(2)); break; case CPUINFO_STR_REGISTER + MB86233_R3: sprintf(info->s, "R3:%08X", GETGPR(3)); break; case CPUINFO_STR_REGISTER + MB86233_R4: sprintf(info->s, "R4:%08X", GETGPR(4)); break; case CPUINFO_STR_REGISTER + MB86233_R5: sprintf(info->s, "R5:%08X", GETGPR(5)); break; case CPUINFO_STR_REGISTER + MB86233_R6: sprintf(info->s, "R6:%08X", GETGPR(6)); break; case CPUINFO_STR_REGISTER + MB86233_R7: sprintf(info->s, "R7:%08X", GETGPR(7)); break; case CPUINFO_STR_REGISTER + MB86233_R8: sprintf(info->s, "R8:%08X", GETGPR(8)); break; case CPUINFO_STR_REGISTER + MB86233_R9: sprintf(info->s, "R9:%08X", GETGPR(9)); break; case CPUINFO_STR_REGISTER + MB86233_R10: sprintf(info->s, "R10:%08X", GETGPR(10)); break; case CPUINFO_STR_REGISTER + MB86233_R11: sprintf(info->s, "R11:%08X", GETGPR(11)); break; case CPUINFO_STR_REGISTER + MB86233_R12: sprintf(info->s, "R12:%08X", GETGPR(12)); break; case CPUINFO_STR_REGISTER + MB86233_R13: sprintf(info->s, "R13:%08X", GETGPR(13)); break; case CPUINFO_STR_REGISTER + MB86233_R14: sprintf(info->s, "R14:%08X", GETGPR(14)); break; case CPUINFO_STR_REGISTER + MB86233_R15: sprintf(info->s, "R15:%08X", GETGPR(15)); break; } }