606 lines
18 KiB
C
606 lines
18 KiB
C
/* This file is included into vb.c and cannot be compiled on its own. */
|
|
#ifdef VBAPI
|
|
|
|
|
|
|
|
/********************************* Constants *********************************/
|
|
|
|
/* Operation IDs */
|
|
#define CPU_HALTING 0
|
|
#define CPU_FATAL 1
|
|
#define CPU_FETCH 2
|
|
#define CPU_ILLEGAL 3
|
|
#define CPU_BITSTRING 4
|
|
#define CPU_FLOATENDO 5
|
|
#define CPU_DOWN 6
|
|
#define CPU_BITWISE 7
|
|
#define CPU_UP 8
|
|
#define CPU_ADD 9
|
|
#define CPU_ADDF_S 10
|
|
#define CPU_ADDI 11
|
|
#define CPU_AND 12
|
|
#define CPU_ANDI 13
|
|
#define CPU_BCOND 14
|
|
#define CPU_CAXI 15
|
|
#define CPU_CLI 16
|
|
#define CPU_CMP 17
|
|
#define CPU_CMPF_S 18
|
|
#define CPU_CVT_SW 19
|
|
#define CPU_CVT_WS 20
|
|
#define CPU_DIV 21
|
|
#define CPU_DIVF_S 22
|
|
#define CPU_DIVU 23
|
|
#define CPU_HALT 24
|
|
#define CPU_IN_B 25
|
|
#define CPU_IN_H 26
|
|
#define CPU_IN_W 27
|
|
#define CPU_JAL 28
|
|
#define CPU_JMP 29
|
|
#define CPU_JR 30
|
|
#define CPU_LD_B 31
|
|
#define CPU_LD_H 32
|
|
#define CPU_LD_W 33
|
|
#define CPU_LDSR 34
|
|
#define CPU_MOV 35
|
|
#define CPU_MOVEA 36
|
|
#define CPU_MOVHI 37
|
|
#define CPU_MPYHW 38
|
|
#define CPU_MUL 39
|
|
#define CPU_MULF_S 40
|
|
#define CPU_MULU 41
|
|
#define CPU_NOT 42
|
|
#define CPU_OR 43
|
|
#define CPU_ORI 44
|
|
#define CPU_OUT_B 45
|
|
#define CPU_OUT_H 46
|
|
#define CPU_OUT_W 47
|
|
#define CPU_RETI 48
|
|
#define CPU_REV 49
|
|
#define CPU_SAR 50
|
|
#define CPU_SEI 51
|
|
#define CPU_SETF 52
|
|
#define CPU_SHL 53
|
|
#define CPU_SHR 54
|
|
#define CPU_ST_B 55
|
|
#define CPU_ST_H 56
|
|
#define CPU_ST_W 57
|
|
#define CPU_STSR 58
|
|
#define CPU_SUB 59
|
|
#define CPU_SUBF_S 60
|
|
#define CPU_TRAP 61
|
|
#define CPU_TRNC_SW 62
|
|
#define CPU_XB 63
|
|
#define CPU_XH 64
|
|
#define CPU_XOR 65
|
|
#define CPU_XORI 66
|
|
|
|
/* Abstract operand types */
|
|
#define CPU_IMP(x) -x-1
|
|
#define CPU_DISP9 1
|
|
#define CPU_DISP26 2
|
|
#define CPU_IMM16S 3
|
|
#define CPU_IMM16U 4
|
|
#define CPU_IMM5S 5
|
|
#define CPU_IMM5U 6
|
|
#define CPU_MEM 7
|
|
#define CPU_REG1 8
|
|
#define CPU_REG2 9
|
|
|
|
/* Functional operand types */
|
|
#define CPU_LITERAL 0
|
|
#define CPU_MEMORY 1
|
|
#define CPU_REGISTER 2
|
|
|
|
/* Bit string operations */
|
|
#define CPU_AND_BS 0
|
|
#define CPU_ANDN_BS 1
|
|
#define CPU_MOV_BS 2
|
|
#define CPU_NOT_BS 3
|
|
#define CPU_OR_BS 4
|
|
#define CPU_ORN_BS 5
|
|
#define CPU_XOR_BS 6
|
|
#define CPU_XORN_BS 7
|
|
|
|
/* Instruction code lengths by opcode */
|
|
static const uint8_t INST_LENGTHS[] = {
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2
|
|
};
|
|
|
|
|
|
|
|
/********************************** Macros ***********************************/
|
|
|
|
/* Master clocks per CPU cycles */
|
|
#define cpuClocks(x) x
|
|
|
|
/* Shorthand */
|
|
#define auxData sim->cpu.aux.data
|
|
|
|
|
|
|
|
/******************************** Lookup Data ********************************/
|
|
|
|
/* Opdefs by opcode */
|
|
static const uint8_t OPDEFS[] = {
|
|
CPU_MOV , CPU_ADD , CPU_SUB , CPU_CMP , /* 000000 */
|
|
CPU_SHL , CPU_SHR , CPU_JMP , CPU_SAR ,
|
|
CPU_MUL , CPU_DIV , CPU_MULU , CPU_DIVU ,
|
|
CPU_OR , CPU_AND , CPU_XOR , CPU_NOT ,
|
|
CPU_MOV , CPU_ADD , CPU_SETF , CPU_CMP , /* 010000 */
|
|
CPU_SHL , CPU_SHR , CPU_CLI , CPU_SAR ,
|
|
CPU_TRAP , CPU_RETI , CPU_HALT , CPU_ILLEGAL ,
|
|
CPU_LDSR , CPU_STSR , CPU_SEI , CPU_BITSTRING,
|
|
CPU_BCOND, CPU_BCOND, CPU_BCOND , CPU_BCOND , /* 100000 */
|
|
CPU_BCOND, CPU_BCOND, CPU_BCOND , CPU_BCOND ,
|
|
CPU_MOVEA, CPU_ADDI , CPU_JR , CPU_JAL ,
|
|
CPU_ORI , CPU_ANDI , CPU_XORI , CPU_MOVHI ,
|
|
CPU_LD_B , CPU_LD_H , CPU_ILLEGAL , CPU_LD_W , /* 110000 */
|
|
CPU_ST_B , CPU_ST_H , CPU_ILLEGAL , CPU_ST_W ,
|
|
CPU_IN_B , CPU_IN_H , CPU_CAXI , CPU_IN_W ,
|
|
CPU_OUT_B, CPU_OUT_H, CPU_FLOATENDO, CPU_OUT_W
|
|
};
|
|
|
|
/* Opdefs by bit string sub-opcode */
|
|
static const uint8_t OPDEFS_BITSTRING[] = {
|
|
CPU_UP , CPU_DOWN , CPU_UP , CPU_DOWN , /* 00000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_BITWISE, CPU_BITWISE, CPU_BITWISE, CPU_BITWISE, /* 01000 */
|
|
CPU_BITWISE, CPU_BITWISE, CPU_BITWISE, CPU_BITWISE,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, /* 10000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, /* 11000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL
|
|
};
|
|
|
|
/* Opdefs by floating-point/Nintendo sub-opcodes */
|
|
static const uint8_t OPDEFS_FLOATENDO[] = {
|
|
CPU_CMPF_S , CPU_ILLEGAL, CPU_CVT_WS , CPU_CVT_SW , /* 000000 */
|
|
CPU_ADDF_S , CPU_SUBF_S , CPU_MULF_S , CPU_DIVF_S ,
|
|
CPU_XB , CPU_XH , CPU_REV , CPU_TRNC_SW,
|
|
CPU_MPYHW , CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, /* 010000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, /* 100000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, /* 110000 */
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL,
|
|
CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL
|
|
};
|
|
|
|
|
|
|
|
/***************************** Callback Handlers *****************************/
|
|
|
|
/* Prepare to execute an instruction */
|
|
#ifndef VB_DIRECT_EXECUTE
|
|
#define VB_ON_EXECUTE sim->onExecute
|
|
#else
|
|
extern int vbxOnExecute(VB *, uint32_t, const uint16_t *, int);
|
|
#define VB_ON_EXECUTE vbxOnExecute
|
|
#endif
|
|
static int cpuExecute(VB *sim) {
|
|
return
|
|
sim->onExecute != NULL &&
|
|
VB_ON_EXECUTE(sim, sim->cpu.pc, sim->cpu.code, sim->cpu.length)
|
|
;
|
|
}
|
|
#undef VB_ON_EXECUTE
|
|
|
|
/* Read a value from the memory bus */
|
|
#ifndef VB_DIRECT_READ
|
|
#define VB_ON_READ sim->onRead
|
|
#else
|
|
extern int vbxOnRead(VB *, uint32_t, int, int32_t *, uint32_t *);
|
|
#define VB_ON_READ vbxOnRead
|
|
#endif
|
|
static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
|
uint32_t cycles = 4; /* TODO: Research this */
|
|
|
|
/* Retrieve the value from the simulation state directly */
|
|
busRead(sim, address, type, value);
|
|
|
|
/* Invoke the callback if available */
|
|
if (
|
|
sim->onRead != NULL &&
|
|
VB_ON_READ(sim, address, type, value, &cycles)
|
|
) return 1;
|
|
|
|
/* Update state */
|
|
sim->cpu.clocks += cpuClocks(cycles);
|
|
return 0;
|
|
}
|
|
#undef VB_ON_READ
|
|
|
|
/* Fetch a code unit from the memory bus */
|
|
#ifndef VB_DIRECT_FETCH
|
|
#define VB_ON_FETCH sim->onFetch
|
|
#else
|
|
extern int vbxOnFetch(VB *, int, uint32_t, int32_t *, uint32_t *);
|
|
#define VB_ON_FETCH vbxOnFetch
|
|
#endif
|
|
static int cpuReadFetch(VB *sim, int fetch, uint32_t address, int32_t *value) {
|
|
uint32_t cycles = 0;
|
|
|
|
/* Retrieve the value from the simulation state directly */
|
|
busRead(sim, address, VB_U16, value);
|
|
|
|
/* Invoke the callback if available */
|
|
if (
|
|
sim->onFetch != NULL &&
|
|
VB_ON_FETCH(sim, fetch, address, value, &cycles)
|
|
) return 1;
|
|
|
|
/* Update state */
|
|
sim->cpu.clocks += cpuClocks(cycles);
|
|
return 0;
|
|
}
|
|
#undef VB_ON_FETCH
|
|
|
|
/* Write a value to the memory bus */
|
|
#ifndef VB_DIRECT_WRITE
|
|
#define VB_ON_WRITE sim->onWrite
|
|
#else
|
|
extern int vbxOnWrite(VB *, uint32_t, int, int32_t *, uint32_t *, int *);
|
|
#define VB_ON_WRITE vbxOnWrite
|
|
#endif
|
|
static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
|
int cancel = 0;
|
|
uint32_t cycles = 3; /* TODO: Research this */
|
|
|
|
/* Invoke the callback if available */
|
|
if (
|
|
sim->onWrite != NULL &&
|
|
VB_ON_WRITE(sim, address, type, &value, &cycles, &cancel)
|
|
) return 1;
|
|
|
|
/* Write the value to the simulation state directly */
|
|
if (!cancel)
|
|
busWrite(sim, address, type, value, 0);
|
|
|
|
/* Update state */
|
|
sim->cpu.clocks += cpuClocks(cycles);
|
|
return 0;
|
|
}
|
|
#undef VB_ON_WRITE
|
|
|
|
|
|
|
|
/****************************** Pipeline Stages ******************************/
|
|
|
|
/* Fetch the code bits for the next instruction */
|
|
static int cpuFetch(VB *sim) {
|
|
int32_t value;
|
|
switch (sim->cpu.step) {
|
|
|
|
case 0:
|
|
sim->cpu.pc = sim->cpu.nextPC;
|
|
/* Fallthrough */
|
|
|
|
case 1:
|
|
|
|
/* Retrieve the first code unit */
|
|
if (cpuReadFetch(sim, 0, sim->cpu.pc, &value)) {
|
|
sim->cpu.step = 1;
|
|
return 1;
|
|
}
|
|
|
|
/* Update state */
|
|
sim->cpu.code[0] = value;
|
|
sim->cpu.length = INST_LENGTHS[value >> 10 & 63];
|
|
sim->cpu.step = 3 - sim->cpu.length;
|
|
|
|
/* Wait any clocks taken */
|
|
if (sim->cpu.clocks != 0)
|
|
return 0;
|
|
|
|
/* Skip fetching a second code unit */
|
|
if (sim->cpu.length == 1)
|
|
goto Step3;
|
|
|
|
/* Fallthrough */
|
|
case 2:
|
|
|
|
/* Retrieve the second code unit */
|
|
if (cpuReadFetch(sim, 1, sim->cpu.pc + 2, &value))
|
|
return 1;
|
|
|
|
/* Update state */
|
|
sim->cpu.code[1] = value;
|
|
sim->cpu.step = 3;
|
|
|
|
/* Wait any clocks taken */
|
|
if (sim->cpu.clocks != 0)
|
|
return 0;
|
|
|
|
/* Fallthrough */
|
|
case 3: Step3:
|
|
|
|
/* Prepare to execute the instruction */
|
|
if (cpuExecute(sim))
|
|
return 1;
|
|
|
|
/* Select operation definition */
|
|
sim->cpu.operation = OPDEFS[sim->cpu.code[0] >> 10];
|
|
switch (sim->cpu.operation) {
|
|
case CPU_BITSTRING:
|
|
sim->cpu.operation =
|
|
OPDEFS_BITSTRING[sim->cpu.code[0] & 31];
|
|
break;
|
|
case CPU_FLOATENDO:
|
|
sim->cpu.operation =
|
|
OPDEFS_FLOATENDO[sim->cpu.code[1] >> 10];
|
|
}
|
|
|
|
/* Update state */
|
|
sim->cpu.step = 0;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**************************** Instruction Helpers ****************************/
|
|
|
|
/* Parse the immediate 16-bit sign-extended value */
|
|
static int32_t cpuGetImm16S(VB *sim) {
|
|
return SignExtend(sim->cpu.code[1], 16);
|
|
}
|
|
|
|
/* Parse the immediate 16-bit zero-filled value */
|
|
static int32_t cpuGetImm16U(VB *sim) {
|
|
return sim->cpu.code[1];
|
|
}
|
|
|
|
/* Resolve the operand value for reg1 */
|
|
static int32_t cpuGetReg1(VB *sim) {
|
|
return sim->cpu.program[sim->cpu.code[0] & 31];
|
|
}
|
|
|
|
/* Supply an operand value for reg2 */
|
|
static void cpuSetReg2(VB *sim, int32_t value) {
|
|
int reg2 = sim->cpu.code[0] >> 5 & 31;
|
|
if (reg2 != 0)
|
|
sim->cpu.program[reg2] = value;
|
|
}
|
|
|
|
/* Memory access instruction */
|
|
static int cpuLD_IN(VB *sim, int type) {
|
|
switch (sim->cpu.step) {
|
|
|
|
case 0:
|
|
auxData.address = cpuGetReg1(sim) + cpuGetImm16S(sim);
|
|
/* Fallthrough */
|
|
|
|
case 1:
|
|
|
|
/* Read the value from memory */
|
|
if (cpuRead(sim, auxData.address, type, &auxData.value)) {
|
|
sim->cpu.step = 1;
|
|
return 1;
|
|
}
|
|
|
|
/* Update state */
|
|
sim->cpu.clocks += cpuClocks(1);
|
|
|
|
/* Wait for clocks taken */
|
|
sim->cpu.step = 2;
|
|
return 0;
|
|
|
|
case 2:
|
|
cpuSetReg2(sim, auxData.value);
|
|
sim->cpu.operation = CPU_FETCH;
|
|
sim->cpu.nextPC += sim->cpu.pc + 4;
|
|
sim->cpu.step = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/************************** Instruction Operations ***************************/
|
|
|
|
/* IN.B */
|
|
static int cpuIN_B(VB *sim) {
|
|
return cpuLD_IN(sim, VB_U8);
|
|
}
|
|
|
|
/* IN.H */
|
|
static int cpuIN_H(VB *sim) {
|
|
return cpuLD_IN(sim, VB_U16);
|
|
}
|
|
|
|
/* IN.W */
|
|
static int cpuIN_W(VB *sim) {
|
|
return cpuLD_IN(sim, VB_S32);
|
|
}
|
|
|
|
/* JMP */
|
|
static int cpuJMP(VB *sim) {
|
|
sim->cpu.nextPC = cpuGetReg1(sim) & 0xFFFFFFFE;
|
|
sim->cpu.clocks += cpuClocks(3);
|
|
sim->cpu.operation = CPU_FETCH;
|
|
/* TODO: Clear prefetch buffer */
|
|
return 0;
|
|
}
|
|
|
|
/* LD.B */
|
|
static int cpuLD_B(VB *sim) {
|
|
return cpuLD_IN(sim, VB_S8);
|
|
}
|
|
|
|
/* LD.H */
|
|
static int cpuLD_H(VB *sim) {
|
|
return cpuLD_IN(sim, VB_S16);
|
|
}
|
|
|
|
/* LD.W */
|
|
static int cpuLD_W(VB *sim) {
|
|
return cpuLD_IN(sim, VB_S32);
|
|
}
|
|
|
|
/* MOVEA */
|
|
static int cpuMOVEA(VB *sim) {
|
|
cpuSetReg2(sim, cpuGetReg1(sim) + cpuGetImm16S(sim));
|
|
sim->cpu.clocks += cpuClocks(1);
|
|
sim->cpu.operation = CPU_FETCH;
|
|
sim->cpu.nextPC = sim->cpu.pc + 4;
|
|
return 0;
|
|
}
|
|
|
|
/* MOVHI */
|
|
static int cpuMOVHI(VB *sim) {
|
|
cpuSetReg2(sim, cpuGetReg1(sim) + (cpuGetImm16U(sim) << 16));
|
|
sim->cpu.clocks += cpuClocks(1);
|
|
sim->cpu.operation = CPU_FETCH;
|
|
sim->cpu.nextPC = sim->cpu.pc + 4;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/***************************** Library Functions *****************************/
|
|
|
|
/* Process component */
|
|
static int cpuEmulate(VB *sim, uint32_t clocks) {
|
|
int brk;
|
|
|
|
/* Process until there are clocks to wait */
|
|
for (;;) {
|
|
|
|
/* The next event is after the time remaining */
|
|
if (sim->cpu.clocks > clocks) {
|
|
sim->cpu.clocks -= clocks;
|
|
return 0;
|
|
}
|
|
|
|
/* Advance forward the CPU's number of clocks */
|
|
if (sim->cpu.clocks != 0) {
|
|
clocks -= sim->cpu.clocks;
|
|
sim->cpu.clocks = 0;
|
|
}
|
|
|
|
/* Processing by operation ID */
|
|
switch (sim->cpu.operation) {
|
|
case CPU_FETCH: brk = cpuFetch(sim); break;
|
|
|
|
case CPU_IN_B : brk = cpuIN_B (sim); break;
|
|
case CPU_IN_H : brk = cpuIN_H (sim); break;
|
|
case CPU_IN_W : brk = cpuIN_W (sim); break;
|
|
case CPU_JMP : brk = cpuJMP (sim); break;
|
|
case CPU_LD_B : brk = cpuLD_B (sim); break;
|
|
case CPU_LD_H : brk = cpuLD_H (sim); break;
|
|
case CPU_LD_W : brk = cpuLD_W (sim); break;
|
|
case CPU_MOVEA: brk = cpuMOVEA(sim); break;
|
|
case CPU_MOVHI: brk = cpuMOVHI(sim); break;
|
|
|
|
default: return -1; /* TODO: Temporary for debugging */
|
|
}
|
|
|
|
/* A callback requested a break */
|
|
if (brk)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Retrieve the value of a system register */
|
|
static uint32_t cpuGetSystemRegister(VB *sim, int index) {
|
|
switch (index) {
|
|
case VB_ADTRE: return sim->cpu.adtre;
|
|
case VB_CHCW : return sim->cpu.chcw.ice << 1;
|
|
case VB_ECR : return
|
|
(uint32_t) sim->cpu.ecr.fecc << 16 |
|
|
(uint32_t) sim->cpu.ecr.eicc;
|
|
case VB_EIPC : return sim->cpu.eipc;
|
|
case VB_EIPSW: return sim->cpu.eipsw;
|
|
case VB_FEPC : return sim->cpu.fepc;
|
|
case VB_FEPSW: return sim->cpu.fepsw;
|
|
case VB_PIR : return 0x00005346;
|
|
case VB_PSW : return
|
|
(uint32_t) sim->cpu.psw.i << 16 |
|
|
(uint32_t) sim->cpu.psw.np << 15 |
|
|
(uint32_t) sim->cpu.psw.ep << 14 |
|
|
(uint32_t) sim->cpu.psw.ae << 13 |
|
|
(uint32_t) sim->cpu.psw.id << 12 |
|
|
(uint32_t) sim->cpu.psw.fro << 9 |
|
|
(uint32_t) sim->cpu.psw.fiv << 8 |
|
|
(uint32_t) sim->cpu.psw.fzd << 7 |
|
|
(uint32_t) sim->cpu.psw.fov << 6 |
|
|
(uint32_t) sim->cpu.psw.fud << 5 |
|
|
(uint32_t) sim->cpu.psw.fpr << 4 |
|
|
(uint32_t) sim->cpu.psw.cy << 3 |
|
|
(uint32_t) sim->cpu.psw.ov << 2 |
|
|
(uint32_t) sim->cpu.psw.s << 1 |
|
|
(uint32_t) sim->cpu.psw.z;
|
|
case VB_TKCW : return 0x000000E0;
|
|
case 29 : return sim->cpu.sr29;
|
|
case 30 : return 0x00000004;
|
|
case 31 : return sim->cpu.sr31;
|
|
}
|
|
return 0x00000000; /* All others */
|
|
}
|
|
|
|
/* Specify a new value for a system register */
|
|
static uint32_t cpuSetSystemRegister(VB*sim,int index,uint32_t value,int debug){
|
|
switch (index) {
|
|
case VB_ADTRE: return sim->cpu.adtre = value & 0xFFFFFFFE;
|
|
case VB_CHCW :
|
|
/* TODO: Configure instruction cache */
|
|
sim->cpu.chcw.ice = value >> 1 & 1;
|
|
return value & 0x00000002;
|
|
case VB_ECR :
|
|
if (debug) {
|
|
sim->cpu.ecr.fecc = value >> 16;
|
|
sim->cpu.ecr.eicc = value;
|
|
}
|
|
return
|
|
(uint32_t) sim->cpu.ecr.fecc << 16 |
|
|
(uint32_t) sim->cpu.ecr.eicc;
|
|
case VB_EIPC : return sim->cpu.eipc = value & 0xFFFFFFFE;
|
|
case VB_EIPSW: return sim->cpu.eipsw = value & 0x000FF3FF;
|
|
case VB_FEPC : return sim->cpu.fepc = value & 0xFFFFFFFE;
|
|
case VB_FEPSW: return sim->cpu.fepsw = value & 0x000FF3FF;
|
|
case VB_PIR : return 0x00005346;
|
|
case VB_PSW :
|
|
sim->cpu.psw.i = value >> 16 & 0xF;
|
|
sim->cpu.psw.np = value >> 15 & 1;
|
|
sim->cpu.psw.ep = value >> 14 & 1;
|
|
sim->cpu.psw.ae = value >> 13 & 1;
|
|
sim->cpu.psw.id = value >> 12 & 1;
|
|
sim->cpu.psw.fro = value >> 9 & 1;
|
|
sim->cpu.psw.fiv = value >> 8 & 1;
|
|
sim->cpu.psw.fzd = value >> 7 & 1;
|
|
sim->cpu.psw.fov = value >> 6 & 1;
|
|
sim->cpu.psw.fud = value >> 5 & 1;
|
|
sim->cpu.psw.fpr = value >> 4 & 1;
|
|
sim->cpu.psw.cy = value >> 3 & 1;
|
|
sim->cpu.psw.ov = value >> 2 & 1;
|
|
sim->cpu.psw.s = value >> 1 & 1;
|
|
sim->cpu.psw.z = value & 1;
|
|
return value & 0x000FF3FF;
|
|
case VB_TKCW : return 0x000000E0;
|
|
case 29 : return sim->cpu.sr29 = value;
|
|
case 30 : return 0x00000004;
|
|
case 31 : return sim->cpu.sr31 = debug ? value :
|
|
*(int32_t *) &value < 0 ? (uint32_t) -*(int32_t *) &value : value;
|
|
}
|
|
return 0x00000000; /* All others */
|
|
}
|
|
|
|
/* Determine how many clocks are guaranteed to process */
|
|
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
|
|
return sim->cpu.clocks < clocks ? sim->cpu.clocks : clocks;
|
|
}
|
|
|
|
#endif /* VBAPI */
|