v810/v810.cpp: make opcode timings a bit more faithful to reality (#11079)

* v810/v810.cpp: make opcode timings a bit more faithful to reality

* v810/v810.cpp: housecleaning [skip ci]
This commit is contained in:
Angelo Salese 2023-04-08 17:31:55 +02:00 committed by GitHub
parent ddfca0cb2c
commit b94a5f9d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 189 additions and 139 deletions

View File

@ -1,11 +1,12 @@
// license:BSD-3-Clause
// copyright-holders:Angelo Salese, Tomasz Slanina
// copyright-holders: Tomasz Slanina, Angelo Salese
/******************************************************************
NEC V810 (upd70732) core
Tomasz Slanina
Angelo Salese
Change Log
- 07/04/2023 - Update opcode timings (Angelo Salese)
- 23/08/2012 - Implemented remaining BSU opcodes (Angelo Salese)
- 21/08/2012 - Fixed SET.F behaviour (Angelo Salese)
- 20/08/2012 - Fixed a sign bug with CVT.WS opcode (Angelo Salese)
@ -18,12 +19,22 @@
TODO:
- CY flag in few floating point opcodes
(all floating point opcodes are NOT tested!)
- traps/interrupts/exceptions
- bitstring opcodes currently makes the emulation to drop to 0%
- timing
- missing opcodes : trap, caxi
- Verify floating point opcodes (single precision IEEE-754 standard)
- CY flag in few floating point opcodes;
- split maskable interrupt lines into separate entities;
- implement trap opcode;
- implement halt opcode;
- implement double exception behaviour;
- implement NP fatal exception;
- implement floating point exceptions;
- verify and improve bitstring opcodes;
- cache handling;
- external bus timing (on load/store opcodes):
\- 3 cycles for ROM
\- 2 cycles for RAM
\- 1 cycle for cache
- pipeline;
- implement caxi opcode;
******************************************************************/
@ -33,7 +44,7 @@
#define clkIF 3
#define clkMEM 3
#define clkIRQ 14
DEFINE_DEVICE_TYPE(V810, v810_device, "v810", "NEC V810")
@ -186,13 +197,14 @@ uint32_t v810_device::GETREG(uint32_t reg)
uint32_t v810_device::opUNDEF(uint32_t op)
{
logerror("V810: Unknown opcode %x @ %x",op,PC-2);
machine().debug_break();
return clkIF;
}
uint32_t v810_device::opMOVr(uint32_t op) // mov reg1, reg2
{
SETREG(GET2,GETREG(GET1));
return clkIF;
return 1;
}
uint32_t v810_device::opMOVEA(uint32_t op) // movea imm16, reg1, reg2
@ -202,7 +214,7 @@ uint32_t v810_device::opMOVEA(uint32_t op) // movea imm16, reg1, reg2
PC+=2;
op2=I16(op2);
SETREG(GET2,op1+op2);
return clkIF;
return 1;
}
uint32_t v810_device::opMOVHI(uint32_t op) // movhi imm16, reg1 ,reg2
@ -212,13 +224,13 @@ uint32_t v810_device::opMOVHI(uint32_t op) // movhi imm16, reg1 ,reg2
op2=UI16(op2);
op2<<=16;
SETREG(GET2,GETREG(GET1)+op2);
return clkIF;
return 1;
}
uint32_t v810_device::opMOVi(uint32_t op) // mov imm5,r2
{
SETREG(GET2,I5(op));
return clkIF;
return 1;
}
uint32_t v810_device::opADDr(uint32_t op) // add r1,r2
@ -230,7 +242,7 @@ uint32_t v810_device::opADDr(uint32_t op) // add r1,r2
CHECK_OVADD(op1,op2,res);
CHECK_ZS(res);
SETREG(GET2,res);
return clkIF;
return 1;
}
uint32_t v810_device::opADDi(uint32_t op) // add imm5,r2
@ -242,7 +254,7 @@ uint32_t v810_device::opADDi(uint32_t op) // add imm5,r2
CHECK_OVADD(op1,op2,res);
CHECK_ZS(res);
SETREG(GET2,res);
return clkIF;
return 1;
}
@ -258,7 +270,7 @@ uint32_t v810_device::opADDI(uint32_t op) // addi imm16, reg1, reg2
CHECK_OVADD(op1,op2,res);
CHECK_ZS(res);
SETREG(GET2,res);
return clkIF;
return 1;
}
uint32_t v810_device::opSUBr(uint32_t op) // sub r1,r2
@ -270,7 +282,7 @@ uint32_t v810_device::opSUBr(uint32_t op) // sub r1,r2
CHECK_OVSUB(op1,op2,res);
CHECK_ZS(res);
SETREG(GET2,res);
return clkIF;
return 1;
}
@ -282,7 +294,7 @@ uint32_t v810_device::opCMPr(uint32_t op) // cmp r1,r2
CHECK_CY(res);
CHECK_OVSUB(op1,op2,res);
CHECK_ZS(res);
return clkIF;
return 1;
}
uint32_t v810_device::opCMPi(uint32_t op) // cmpi imm5,r2
@ -293,7 +305,7 @@ uint32_t v810_device::opCMPi(uint32_t op) // cmpi imm5,r2
CHECK_CY(res);
CHECK_OVSUB(op1,op2,res);
CHECK_ZS(res);
return clkIF;
return 1;
}
uint32_t v810_device::opSETFi(uint32_t op) // setf imm5,r2
@ -333,42 +345,41 @@ uint32_t v810_device::opSETFi(uint32_t op) // setf imm5,r2
case 7: //ble
res=GET_Z||(GET_S^GET_OV);
break;
break;
case 8: //bnv
res=!GET_OV;
break;
break;
case 9: //bnl
res=!GET_CY;
break;
break;
case 10: //bne
res=!GET_Z;
break;
break;
case 11: //bh
res=!(GET_Z||GET_CY);
break;
break;
case 12: //bp
res=!GET_S;
break;
break;
case 13: //nop
break;
case 14: //bge
res=!(GET_OV^GET_S);
break;
break;
case 15: //bgt
res=!(GET_Z||(GET_OV^GET_S));
break;
}
SETREG(GET2,res);
return clkIF;
return 1;
}
@ -380,7 +391,7 @@ uint32_t v810_device::opANDr(uint32_t op) // and r1,r2
CHECK_ZS(op2);
SET_OV(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opANDI(uint32_t op) // andi imm16,r1,r2
@ -394,7 +405,7 @@ uint32_t v810_device::opANDI(uint32_t op) // andi imm16,r1,r2
SET_OV(0);
SET_S(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opORr(uint32_t op) // or r1,r2
@ -405,7 +416,7 @@ uint32_t v810_device::opORr(uint32_t op) // or r1,r2
CHECK_ZS(op2);
SET_OV(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opORI(uint32_t op) // ori imm16,r1,r2
@ -419,7 +430,7 @@ uint32_t v810_device::opORI(uint32_t op) // ori imm16,r1,r2
SET_OV(0);
SET_S(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opXORr(uint32_t op) // xor r1,r2
@ -430,7 +441,7 @@ uint32_t v810_device::opXORr(uint32_t op) // xor r1,r2
CHECK_ZS(op2);
SET_OV(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
@ -438,14 +449,14 @@ uint32_t v810_device::opLDSR(uint32_t op) // ldsr reg2,regID
{
uint32_t op1=UI5(op);
SETREG(32+op1,GETREG(GET2));
return clkIF;
return 2;
}
uint32_t v810_device::opSTSR(uint32_t op) // ldsr regID,reg2
{
uint32_t op1=UI5(op);
SETREG(GET2,GETREG(32+op1));
return clkIF;
return 2;
}
@ -460,7 +471,7 @@ uint32_t v810_device::opXORI(uint32_t op) // xori imm16,r1,r2
SET_OV(0);
SET_S(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opNOTr(uint32_t op) // not r1,r2
@ -470,7 +481,7 @@ uint32_t v810_device::opNOTr(uint32_t op) // not r1,r2
CHECK_ZS(op2);
SET_OV(0);
SETREG(GET2,op2);
return clkIF;
return 1;
}
uint32_t v810_device::opSHLr(uint32_t op) // shl r1,r2
@ -490,7 +501,7 @@ uint32_t v810_device::opSHLr(uint32_t op) // shl r1,r2
SETREG(GET2,tmp&0xffffffff);
CHECK_ZS(GETREG(GET2));
}
return clkIF;
return 1;
}
uint32_t v810_device::opSHLi(uint32_t op) // shl imm5,r2
@ -509,7 +520,7 @@ uint32_t v810_device::opSHLi(uint32_t op) // shl imm5,r2
SETREG(GET2,tmp&0xffffffff);
}
CHECK_ZS(GETREG(GET2));
return clkIF;
return 1;
}
uint32_t v810_device::opSHRr(uint32_t op) // shr r1,r2
@ -527,7 +538,7 @@ uint32_t v810_device::opSHRr(uint32_t op) // shr r1,r2
SETREG(GET2,(tmp>>1)&0xffffffff);
}
CHECK_ZS(GETREG(GET2));
return clkIF;
return 1;
}
uint32_t v810_device::opSHRi(uint32_t op) // shr imm5,r2
@ -545,7 +556,7 @@ uint32_t v810_device::opSHRi(uint32_t op) // shr imm5,r2
SETREG(GET2,tmp&0xffffffff);
}
CHECK_ZS(GETREG(GET2));
return clkIF;
return 1;
}
uint32_t v810_device::opSARr(uint32_t op) // sar r1,r2
@ -564,7 +575,7 @@ uint32_t v810_device::opSARr(uint32_t op) // sar r1,r2
SETREG(GET2,tmp);
}
CHECK_ZS(GETREG(GET2));
return clkIF;
return 1;
}
uint32_t v810_device::opSARi(uint32_t op) // sar imm5,r2
@ -582,13 +593,13 @@ uint32_t v810_device::opSARi(uint32_t op) // sar imm5,r2
SETREG(GET2,tmp);
}
CHECK_ZS(GETREG(GET2));
return clkIF;
return 1;
}
uint32_t v810_device::opJMPr(uint32_t op)
{
PC=GETREG(GET1)&~1;
return clkIF+2;
return 3;
}
@ -596,7 +607,7 @@ uint32_t v810_device::opJR(uint32_t op)
{
uint32_t tmp=R_OP(PC);
PC=PC-2+(D26(op,tmp)&~1);
return clkIF+2;
return 3;
}
uint32_t v810_device::opJAL(uint32_t op)
@ -607,26 +618,28 @@ uint32_t v810_device::opJAL(uint32_t op)
PC+=D26(op,tmp);
PC-=4;
PC&=~1;
return clkIF+2;
return 3;
}
uint32_t v810_device::opEI(uint32_t op)
{
SET_ID(0);
return clkIF;
return 1;
}
uint32_t v810_device::opDI(uint32_t op)
{
SET_ID(1);
return clkIF;
return 1;
}
uint32_t v810_device::opTRAP(uint32_t op)
{
printf("V810: TRAP @ %X\n",PC-2);
return clkIF;
logerror("V810: TRAP @ %X\n", PC - 2);
machine().debug_break();
// TODO: assume same as irq time
return clkIRQ;
}
uint32_t v810_device::opRETI(uint32_t op)
@ -638,13 +651,14 @@ uint32_t v810_device::opRETI(uint32_t op)
PC = EIPC;
PSW = EIPSW;
}
return clkIF;
return 1;
}
uint32_t v810_device::opHALT(uint32_t op)
{
printf("V810: HALT @ %X\n",PC-2);
return clkIF;
logerror("V810: HALT @ %X\n",PC-2);
machine().debug_break();
return 1;
}
uint32_t v810_device::opB(uint32_t op)
@ -654,73 +668,74 @@ uint32_t v810_device::opB(uint32_t op)
{
case 0: //bv
doBranch=GET_OV;
break;
break;
case 1: //bl
doBranch=GET_CY;
break;
break;
case 2: //be
doBranch=GET_Z;
break;
break;
case 3: //bnh
doBranch=GET_Z||GET_CY;
break;
break;
case 4: //bn
doBranch=GET_S;
break;
break;
case 5: //br
doBranch=1;
break;
break;
case 6: //blt
doBranch=GET_S^GET_OV;
break;
break;
case 7: //ble
doBranch=GET_Z||(GET_S^GET_OV);
break;
break;
case 8: //bnv
doBranch=!GET_OV;
break;
break;
case 9: //bnl
doBranch=!GET_CY;
break;
break;
case 10: //bne
doBranch=!GET_Z;
break;
break;
case 11: //bh
doBranch=!(GET_Z||GET_CY);
break;
break;
case 12: //bp
doBranch=!GET_S;
break;
break;
case 13: //nop
break;
break;
case 14: //bge
doBranch=!(GET_OV^GET_S);
break;
break;
case 15: //bgt
doBranch=!(GET_Z||(GET_OV^GET_S));
break;
break;
}
if(doBranch)
{
PC=PC-2+(D9(op)&~1);
PC = PC - 2 + (D9(op) &~1);
return 3;
}
return clkIF;
return 1;
}
uint32_t v810_device::opLDB(uint32_t op) // ld.b disp16[reg1],reg2
@ -732,7 +747,7 @@ uint32_t v810_device::opLDB(uint32_t op) // ld.b disp16[reg1],reg2
tmp=R_B(tmp);
tmp|=(tmp&0x80)?0xffffff00:0;
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opLDH(uint32_t op) // ld.h disp16[reg1],reg2
@ -744,7 +759,7 @@ uint32_t v810_device::opLDH(uint32_t op) // ld.h disp16[reg1],reg2
tmp=R_H(tmp&~1);
tmp|=(tmp&0x8000)?0xffff0000:0;
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opLDW(uint32_t op) // ld.w disp16[reg1],reg2
@ -755,7 +770,7 @@ uint32_t v810_device::opLDW(uint32_t op) // ld.w disp16[reg1],reg2
tmp+=GETREG(GET1);
tmp=R_W(tmp&~3);
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opINB(uint32_t op) // in.b disp16[reg1],reg2
@ -766,14 +781,15 @@ uint32_t v810_device::opINB(uint32_t op) // in.b disp16[reg1],reg2
tmp+=GETREG(GET1);
tmp=RIO_B(tmp);
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opCAXI(uint32_t op) // caxi disp16[reg1],reg2
{
printf("V810 CAXI execute\n");
PC+=2;
return clkIF;
// TODO: check me
return 1;
}
uint32_t v810_device::opINH(uint32_t op) // in.h disp16[reg1],reg2
@ -784,7 +800,7 @@ uint32_t v810_device::opINH(uint32_t op) // in.h disp16[reg1],reg2
tmp+=GETREG(GET1);
tmp=RIO_H(tmp&~1);
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opINW(uint32_t op) // in.w disp16[reg1],reg2
@ -795,7 +811,7 @@ uint32_t v810_device::opINW(uint32_t op) // in.w disp16[reg1],reg2
tmp+=GETREG(GET1);
tmp=RIO_W(tmp&~3);
SETREG(GET2,tmp);
return clkIF+clkMEM;
return 2+clkMEM;
}
uint32_t v810_device::opSTB(uint32_t op) // st.b reg2, disp16[reg1]
@ -805,7 +821,7 @@ uint32_t v810_device::opSTB(uint32_t op) // st.b reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
W_B(tmp,GETREG(GET2)&0xff);
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opSTH(uint32_t op) // st.h reg2, disp16[reg1]
@ -815,7 +831,7 @@ uint32_t v810_device::opSTH(uint32_t op) // st.h reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
W_H(tmp&~1,GETREG(GET2)&0xffff);
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opSTW(uint32_t op) // st.w reg2, disp16[reg1]
@ -825,7 +841,7 @@ uint32_t v810_device::opSTW(uint32_t op) // st.w reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
W_W(tmp&~3,GETREG(GET2));
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opOUTB(uint32_t op) // out.b reg2, disp16[reg1]
@ -835,7 +851,7 @@ uint32_t v810_device::opOUTB(uint32_t op) // out.b reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
WIO_B(tmp,GETREG(GET2)&0xff);
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opOUTH(uint32_t op) // out.h reg2, disp16[reg1]
@ -845,7 +861,7 @@ uint32_t v810_device::opOUTH(uint32_t op) // out.h reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
WIO_H(tmp&~1,GETREG(GET2)&0xffff);
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opOUTW(uint32_t op) // out.w reg2, disp16[reg1]
@ -855,7 +871,7 @@ uint32_t v810_device::opOUTW(uint32_t op) // out.w reg2, disp16[reg1]
tmp=D16(tmp);
tmp+=GETREG(GET1);
WIO_W(tmp&~3,GETREG(GET2));
return clkIF+clkMEM;
return 1+clkMEM;
}
uint32_t v810_device::opMULr(uint32_t op) // mul r1,r2
@ -872,7 +888,7 @@ uint32_t v810_device::opMULr(uint32_t op) // mul r1,r2
SET_CY((tmp!=0));
SETREG(GET2,op2);
SETREG(30,tmp);
return clkIF;
return 13;
}
uint32_t v810_device::opMULUr(uint32_t op) // mulu r1,r2
@ -889,7 +905,7 @@ uint32_t v810_device::opMULUr(uint32_t op) // mulu r1,r2
SET_CY((tmp!=0));
SETREG(GET2,op2);
SETREG(30,tmp);
return clkIF;
return 13;
}
uint32_t v810_device::opDIVr(uint32_t op) // div r1,r2
@ -904,8 +920,11 @@ uint32_t v810_device::opDIVr(uint32_t op) // div r1,r2
CHECK_ZS(GETREG(GET2));
}
else
printf("DIVr divide by zero?\n");
return clkIF;
{
//machine().debug_break();
throw emu_fatalerror("DIVr divide by zero\n");
}
return 38;
}
uint32_t v810_device::opDIVUr(uint32_t op) // divu r1,r2
@ -920,11 +939,14 @@ uint32_t v810_device::opDIVUr(uint32_t op) // divu r1,r2
CHECK_ZS(GETREG(GET2));
}
else
printf("DIVUr divide by zero?\n");
return clkIF;
{
//machine().debug_break();
throw emu_fatalerror("DIVUr divide by zero\n");
}
return 38;
}
void v810_device::opADDF(uint32_t op)
uint32_t v810_device::opADDF(uint32_t op)
{
//TODO: CY
float val1=u2f(GETREG(GET1));
@ -934,9 +956,10 @@ void v810_device::opADDF(uint32_t op)
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
SETREG(GET2,f2u(val2));
return 24;
}
void v810_device::opSUBF(uint32_t op)
uint32_t v810_device::opSUBF(uint32_t op)
{
float val1=u2f(GETREG(GET1));
float val2=u2f(GETREG(GET2));
@ -946,9 +969,10 @@ void v810_device::opSUBF(uint32_t op)
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
SETREG(GET2,f2u(val2));
return 26;
}
void v810_device::opMULF(uint32_t op)
uint32_t v810_device::opMULF(uint32_t op)
{
//TODO: CY
float val1=u2f(GETREG(GET1));
@ -958,9 +982,10 @@ void v810_device::opMULF(uint32_t op)
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
SETREG(GET2,f2u(val2));
return 27;
}
void v810_device::opDIVF(uint32_t op)
uint32_t v810_device::opDIVF(uint32_t op)
{
//TODO: CY
float val1=u2f(GETREG(GET1));
@ -969,22 +994,25 @@ void v810_device::opDIVF(uint32_t op)
if(val1!=0)
val2/=val1;
else
printf("DIVF divide by zero?\n");
throw emu_fatalerror("DIVF divide by zero\n");
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
SETREG(GET2,f2u(val2));
return 44;
}
void v810_device::opTRNC(uint32_t op)
uint32_t v810_device::opTRNC(uint32_t op)
{
float val1=u2f(GETREG(GET1));
SET_OV(0);
SET_Z((val1==0.0f)?1:0);
SET_S((val1<0.0f)?1:0);
SETREG(GET2,(int32_t)val1);
// TODO: unknown
return 18;
}
void v810_device::opCMPF(uint32_t op)
uint32_t v810_device::opCMPF(uint32_t op)
{
float val1=u2f(GETREG(GET1));
float val2=u2f(GETREG(GET2));
@ -993,18 +1021,22 @@ void v810_device::opCMPF(uint32_t op)
val2-=val1;
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
// TODO: unknown
return 18;
}
void v810_device::opCVTS(uint32_t op)
uint32_t v810_device::opCVTS(uint32_t op)
{
float val1=u2f(GETREG(GET1));
SET_OV(0);
SET_Z((val1==0.0f)?1:0);
SET_S((val1<0.0f)?1:0);
SETREG(GET2,(int32_t)val1);
// TODO: unknown
return 18;
}
void v810_device::opCVTW(uint32_t op)
uint32_t v810_device::opCVTW(uint32_t op)
{
//TODO: CY
float val1=(int32_t)GETREG(GET1);
@ -1012,9 +1044,11 @@ void v810_device::opCVTW(uint32_t op)
SET_Z((val1==0.0f)?1:0);
SET_S((val1<0.0f)?1:0);
SETREG(GET2,f2u(val1));
// TODO: unknown
return 18;
}
void v810_device::opMPYHW(uint32_t op)
uint32_t v810_device::opMPYHW(uint32_t op)
{
int val1=(GETREG(GET1) & 0xffff);
int val2=(GETREG(GET2) & 0xffff);
@ -1023,9 +1057,11 @@ void v810_device::opMPYHW(uint32_t op)
SET_Z((val2==0.0f)?1:0);
SET_S((val2<0.0f)?1:0);
SETREG(GET2,val2);
// TODO: unknown
return 18;
}
void v810_device::opXB(uint32_t op)
uint32_t v810_device::opXB(uint32_t op)
{
int val=GETREG(GET2);
SET_OV(0);
@ -1033,10 +1069,12 @@ void v810_device::opXB(uint32_t op)
SET_Z((val==0.0f)?1:0);
SET_S((val<0.0f)?1:0);
SETREG(GET2,val);
// TODO: unknown
return 18;
}
void v810_device::opXH(uint32_t op)
uint32_t v810_device::opXH(uint32_t op)
{
int val=GETREG(GET2);
SET_OV(0);
@ -1044,49 +1082,56 @@ void v810_device::opXH(uint32_t op)
SET_Z((val==0.0f)?1:0);
SET_S((val<0.0f)?1:0);
SETREG(GET2,val);
// TODO: unknown
return 18;
}
uint32_t v810_device::opFpoint(uint32_t op)
{
uint32_t tmp=R_OP(PC);
uint32_t op_cycles = 0;
PC+=2;
switch((tmp&0xfc00)>>10)
{
case 0x0: opCMPF(op);break;
case 0x2: opCVTW(op);break;
case 0x3: opCVTS(op);break;
case 0x4: opADDF(op);break;
case 0x5: opSUBF(op);break;
case 0x6: opMULF(op);break;
case 0x7: opDIVF(op);break;
case 0x8: opXB(op); break; // *
case 0x9: opXH(op); break; // *
case 0xb: opTRNC(op);break;
case 0xc: opMPYHW(op); break; // *
// * <- Virtual Boy specific?
default: printf("Floating point %02x\n",(tmp&0xfc00) >> 10);break;
// TODO: (*) denotes Virtual Boy specific opcodes
// likely needs co-processor override
case 0x0: op_cycles = opCMPF(op);break;
case 0x2: op_cycles = opCVTW(op);break;
case 0x3: op_cycles = opCVTS(op);break;
case 0x4: op_cycles = opADDF(op);break;
case 0x5: op_cycles = opSUBF(op);break;
case 0x6: op_cycles = opMULF(op);break;
case 0x7: op_cycles = opDIVF(op);break;
case 0x8: op_cycles = opXB(op); break; // (*)
case 0x9: op_cycles = opXH(op); break; // (*)
case 0xb: op_cycles = opTRNC(op);break;
case 0xc: op_cycles = opMPYHW(op); break; // (*)
default:
throw emu_fatalerror("Floating point unknown type %02x\n",(tmp&0xfc00) >> 10);
break;
}
return clkIF+1;
return op_cycles;
}
/* TODO: clocks */
// TODO: makes host performance to dip
// TODO: verify atomicity wrt interrupts & DRQ
// Use scenario: pcfx reading from CD data port with no increment of source address.
uint32_t v810_device::opBSU(uint32_t op)
{
if(!(op & 8))
fatalerror("V810: unknown BSU opcode %04x\n",op);
throw emu_fatalerror("V810: unknown BSU opcode %04x\n",op);
{
uint32_t srcbit,dstbit,src,dst,size;
uint32_t dsttmp,tmp;
uint32_t dsttmp, tmp;
uint8_t srctmp;
// printf("BDST %08x BSRC %08x SIZE %08x DST %08x SRC %08x\n",R26,R27,R28,R29,R30);
dstbit = R26 & 0x1f;
srcbit = R27 & 0x1f;
size = R28;
dst = R29 & ~3;
src = R30 & ~3;
uint32_t dstbit = R26 & 0x1f;
uint32_t srcbit = R27 & 0x1f;
uint32_t size = R28;
uint32_t dst = R29 & ~3;
uint32_t src = R30 & ~3;
switch(op & 0xf)
{
@ -1154,7 +1199,8 @@ uint32_t v810_device::opBSU(uint32_t op)
W_W(dst,tmp);
break;
default: fatalerror("V810: unemulated BSU opcode %04x\n",op);
default:
throw emu_fatalerror("V810: unemulated BSU opcode %04x\n",op);
}
srcbit++;
@ -1178,10 +1224,12 @@ uint32_t v810_device::opBSU(uint32_t op)
R30 = src;
if(size != 0)
PC-=2;
PC -= 2;
}
return clkIF+1; //TODO: correct?
// TODO: all bitstring timings implied for vboy 16-bit ext bus
// TODO: search type BSU takes 4 cycles
return 12;
}
const v810_device::opcode_func v810_device::s_OpCodeTable[64] =
@ -1348,6 +1396,8 @@ void v810_device::device_reset()
ECR = 0x0000fff0;
}
// TODO: unsafe on different irq levels asserted at same time
// TODO: sketchy, lacks fatal & double exceptions
void v810_device::take_interrupt()
{
EIPC = PC;
@ -1364,7 +1414,7 @@ void v810_device::take_interrupt()
SET_ID(1);
PSW |= num << 16;
m_icount-= clkIF;
m_icount -= clkIRQ;
}
void v810_device::execute_run()

View File

@ -178,17 +178,17 @@ private:
uint32_t opMULUr(uint32_t op);
uint32_t opDIVr(uint32_t op);
uint32_t opDIVUr(uint32_t op);
void opADDF(uint32_t op);
void opSUBF(uint32_t op);
void opMULF(uint32_t op);
void opDIVF(uint32_t op);
void opTRNC(uint32_t op);
void opCMPF(uint32_t op);
void opCVTS(uint32_t op);
void opCVTW(uint32_t op);
void opMPYHW(uint32_t op);
void opXB(uint32_t op);
void opXH(uint32_t op);
uint32_t opADDF(uint32_t op);
uint32_t opSUBF(uint32_t op);
uint32_t opMULF(uint32_t op);
uint32_t opDIVF(uint32_t op);
uint32_t opTRNC(uint32_t op);
uint32_t opCMPF(uint32_t op);
uint32_t opCVTS(uint32_t op);
uint32_t opCVTW(uint32_t op);
uint32_t opMPYHW(uint32_t op);
uint32_t opXB(uint32_t op);
uint32_t opXH(uint32_t op);
uint32_t opFpoint(uint32_t op);
uint32_t opBSU(uint32_t op);
void take_interrupt();