Add missing files from last commit.
This commit is contained in:
parent
9312de19ac
commit
f822488656
89 changed files with 18428 additions and 6383 deletions
2
src/386.h
Normal file
2
src/386.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
extern void cpu_386_flags_extract();
|
||||
extern void cpu_386_flags_rebuild();
|
||||
499
src/386_ops.h
Normal file
499
src/386_ops.h
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
#include "x86_ops.h"
|
||||
|
||||
OpFn *x86_opcodes;
|
||||
OpFn *x86_opcodes_0f;
|
||||
|
||||
static inline void PUSH_W(uint16_t val)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememw(ss, ESP - 2, val); if (abrt) return;
|
||||
ESP -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss, (SP - 2) & 0xFFFF, val); if (abrt) return;
|
||||
SP -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void PUSH_L(uint32_t val)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememl(ss, ESP - 4, val); if (abrt) return;
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememl(ss, (SP - 4) & 0xFFFF, val); if (abrt) return;
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t POP_W()
|
||||
{
|
||||
uint16_t ret;
|
||||
if (stack32)
|
||||
{
|
||||
ret = readmemw(ss, ESP); if (abrt) return 0;
|
||||
ESP += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = readmemw(ss, SP); if (abrt) return 0;
|
||||
SP += 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t POP_L()
|
||||
{
|
||||
uint32_t ret;
|
||||
if (stack32)
|
||||
{
|
||||
ret = readmeml(ss, ESP); if (abrt) return 0;
|
||||
ESP += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = readmeml(ss, SP); if (abrt) return 0;
|
||||
SP += 4;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "x86_ops_arith.h"
|
||||
#include "x86_ops_atomic.h"
|
||||
#include "x86_ops_bcd.h"
|
||||
#include "x86_ops_bit.h"
|
||||
#include "x86_ops_bitscan.h"
|
||||
#include "x86_ops_call.h"
|
||||
#include "x86_ops_flag.h"
|
||||
#include "x86_ops_fpu.h"
|
||||
#include "x86_ops_inc_dec.h"
|
||||
#include "x86_ops_int.h"
|
||||
#include "x86_ops_io.h"
|
||||
#include "x86_ops_jump.h"
|
||||
#include "x86_ops_misc.h"
|
||||
#include "x86_ops_mov.h"
|
||||
#include "x86_ops_mov_ctrl.h"
|
||||
#include "x86_ops_mov_seg.h"
|
||||
#include "x86_ops_movx.h"
|
||||
#include "x86_ops_msr.h"
|
||||
#include "x86_ops_mul.h"
|
||||
#include "x86_ops_pmode.h"
|
||||
#include "x86_ops_prefix.h"
|
||||
#include "x86_ops_rep.h"
|
||||
#include "x86_ops_ret.h"
|
||||
#include "x86_ops_set.h"
|
||||
#include "x86_ops_shift.h"
|
||||
#include "x86_ops_stack.h"
|
||||
#include "x86_ops_string.h"
|
||||
#include "x86_ops_xchg.h"
|
||||
|
||||
static int ILLEGAL(uint32_t fetchdat)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op0F_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int opcode = fetchdat & 0xff;
|
||||
pc++;
|
||||
|
||||
return x86_opcodes_0f[opcode](fetchdat >> 8);
|
||||
}
|
||||
static int op0F_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int opcode = fetchdat & 0xff;
|
||||
pc++;
|
||||
|
||||
return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8);
|
||||
}
|
||||
static int op0F_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int opcode = fetchdat & 0xff;
|
||||
pc++;
|
||||
|
||||
return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8);
|
||||
}
|
||||
static int op0F_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int opcode = fetchdat & 0xff;
|
||||
pc++;
|
||||
|
||||
return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8);
|
||||
}
|
||||
|
||||
void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f)
|
||||
{
|
||||
x86_opcodes = opcodes;
|
||||
x86_opcodes_0f = opcodes_0f;
|
||||
}
|
||||
|
||||
OpFn ops_286_0f[1024] =
|
||||
{
|
||||
/*16-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*32-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*16-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*32-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
};
|
||||
|
||||
OpFn ops_386_0f[1024] =
|
||||
{
|
||||
/*16-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*32-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*16-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*32-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL,
|
||||
};
|
||||
|
||||
OpFn ops_286[1024] =
|
||||
{
|
||||
/*16-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
|
||||
|
||||
/*32-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
|
||||
|
||||
/*16-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
|
||||
|
||||
/*32-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
|
||||
};
|
||||
|
||||
OpFn ops_386[1024] =
|
||||
{
|
||||
/*16-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, op_FS, op_GS, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_w_a16, ILLEGAL, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16,
|
||||
|
||||
/*32-bit data, 16-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16,
|
||||
/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l,
|
||||
/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, op_ES, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, op_SS, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI,
|
||||
/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI,
|
||||
/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, op_FS, op_GS, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a16, op81_l_a16, ILLEGAL, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16,
|
||||
/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm,
|
||||
|
||||
/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD,
|
||||
/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16,
|
||||
/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16,
|
||||
|
||||
/*16-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32,
|
||||
/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w,
|
||||
/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, op_ES, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, op_SS, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI,
|
||||
/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI,
|
||||
/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, op_FS, op_GS, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a32, op81_w_a32, ILLEGAL, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32,
|
||||
/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm,
|
||||
|
||||
/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET,
|
||||
/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32,
|
||||
/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32,
|
||||
|
||||
/*32-bit data, 32-bit addr*/
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/
|
||||
/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32,
|
||||
/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l,
|
||||
/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, op_ES, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, op_CS, opDAS,
|
||||
/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, op_SS, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, op_DS, opAAS,
|
||||
|
||||
/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI,
|
||||
/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI,
|
||||
/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, op_FS, op_GS, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32,
|
||||
/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE,
|
||||
|
||||
/*80*/ op80_a32, op81_l_a32, ILLEGAL, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32,
|
||||
/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF,
|
||||
/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32,
|
||||
/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm,
|
||||
|
||||
/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD,
|
||||
/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32,
|
||||
/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX,
|
||||
/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32,
|
||||
};
|
||||
|
|
@ -11,9 +11,13 @@
|
|||
2 clocks - fetch opcode 2 etc*/
|
||||
#include <stdio.h>
|
||||
#include "ibm.h"
|
||||
#include "x86.h"
|
||||
#include "mem.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "keyboard.h"
|
||||
#include "mem.h"
|
||||
#include "pic.h"
|
||||
#include "timer.h"
|
||||
#include "x86.h"
|
||||
|
||||
int nextcyc=0;
|
||||
int cycdiff;
|
||||
|
|
@ -21,7 +25,6 @@ int is8086=0;
|
|||
|
||||
int memcycs;
|
||||
int nopageerrors=0;
|
||||
float cassettetime;
|
||||
|
||||
void FETCHCOMPLETE();
|
||||
|
||||
|
|
@ -84,40 +87,21 @@ void writememl(uint32_t s, uint32_t a, uint32_t v)
|
|||
else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v;
|
||||
}
|
||||
|
||||
int lldt=0;
|
||||
int notpresent;
|
||||
uint16_t oldflags;
|
||||
|
||||
void dumpregs();
|
||||
int incga;
|
||||
uint32_t old8,old82,old83;
|
||||
uint16_t oldcs;
|
||||
int oldcpl;
|
||||
|
||||
int dlE=0;
|
||||
/*#define CS (cs>>4)
|
||||
#define DS (ds>>4)
|
||||
#define ES (es>>4)
|
||||
#define SS (ss>>4)*/
|
||||
|
||||
//#define loadseg(a) ((a)<<4)
|
||||
|
||||
int keyboardtimer;
|
||||
int tempc;
|
||||
int bxcheck=0,spcheck=0;
|
||||
uint16_t getword();
|
||||
int count40=0;
|
||||
int dosfunc;
|
||||
uint8_t opcode;
|
||||
int times=0;
|
||||
uint16_t pc2,pc3;
|
||||
int pit0=1;
|
||||
int noint=0;
|
||||
|
||||
int output=0;
|
||||
|
||||
int shadowbios=0;
|
||||
|
||||
int inint=0;
|
||||
int ins=0;
|
||||
//#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a))
|
||||
|
||||
|
|
@ -266,6 +250,13 @@ inline void FETCHCLEAR()
|
|||
}*/
|
||||
}
|
||||
|
||||
static uint16_t getword()
|
||||
{
|
||||
uint8_t temp=FETCH();
|
||||
return temp|(FETCH()<<8);
|
||||
}
|
||||
|
||||
|
||||
/*EA calculation*/
|
||||
|
||||
/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod
|
||||
|
|
@ -366,7 +357,7 @@ void makemod1table()
|
|||
mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds;
|
||||
}
|
||||
|
||||
void fetcheal()
|
||||
static void fetcheal()
|
||||
{
|
||||
if (!mod && rm==6) { eaaddr=getword(); easeg=ds; FETCHADD(6); }
|
||||
else
|
||||
|
|
@ -395,67 +386,6 @@ void fetcheal()
|
|||
}
|
||||
}
|
||||
|
||||
/*void fetchea()
|
||||
{
|
||||
rmdat=readmemb(cs+pc); pc++;
|
||||
reg=(rmdat>>3)&7;
|
||||
mod=rmdat>>6;
|
||||
rm=rmdat&7;
|
||||
switch (mod)
|
||||
{
|
||||
case 0:
|
||||
switch (rm)
|
||||
{
|
||||
case 0: eaaddr=BX+SI; easeg=ds; if (!AT) cycles-=7; break;
|
||||
case 1: eaaddr=BX+DI; easeg=ds; if (!AT) cycles-=8; break;
|
||||
case 2: eaaddr=BP+SI; easeg=ss; if (!AT) cycles-=8; break;
|
||||
case 3: eaaddr=BP+DI; easeg=ss; if (!AT) cycles-=7; break;
|
||||
case 4: eaaddr=SI; easeg=ds; if (!AT) cycles-=5; break;
|
||||
case 5: eaaddr=DI; easeg=ds; if (!AT) cycles-=5; break;
|
||||
case 6: eaaddr=getword(); easeg=ds; if (!AT) cycles-=6; break;
|
||||
case 7: eaaddr=BX; easeg=ds; if (!AT) cycles-=5; break;
|
||||
}
|
||||
if (AT && !(rm&4)) cycles--;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
eaaddr=readmemb(cs+pc); pc++;
|
||||
if (eaaddr&0x80) eaaddr|=0xFF00;
|
||||
// if (output) printf("EAADDR %04X ",eaaddr);
|
||||
switch (rm)
|
||||
{
|
||||
case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break;
|
||||
case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break;
|
||||
case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break;
|
||||
case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break;
|
||||
case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break;
|
||||
case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break;
|
||||
case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break;
|
||||
case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break;
|
||||
}
|
||||
if (AT && !(rm&4)) cycles--;
|
||||
// if (output) printf("%04X %04X",eaaddr,BX);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
eaaddr=getword();
|
||||
switch (rm)
|
||||
{
|
||||
case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break;
|
||||
case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break;
|
||||
case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break;
|
||||
case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break;
|
||||
case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break;
|
||||
case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break;
|
||||
case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break;
|
||||
case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break;
|
||||
}
|
||||
if (AT && !(rm&4)) cycles--;
|
||||
break;
|
||||
}
|
||||
eaaddr&=0xFFFF;
|
||||
}*/
|
||||
|
||||
static inline uint8_t geteab()
|
||||
{
|
||||
if (mod==3)
|
||||
|
|
@ -562,56 +492,39 @@ void makeznptable()
|
|||
}
|
||||
int timetolive=0;
|
||||
|
||||
uint8_t cpu_readop(uint32_t addr) { return readmemb(addr); }
|
||||
uint8_t cpu_readmem20(uint32_t addr) { return readmemb(addr); }
|
||||
|
||||
void cpu_writemem20(uint32_t addr, uint8_t val) { writememb(addr,val); }
|
||||
|
||||
uint16_t getword()
|
||||
{
|
||||
uint8_t temp=FETCH();
|
||||
return temp|(FETCH()<<8);
|
||||
// pc+=2;
|
||||
// return readmemw(cs,(pc-2));
|
||||
}
|
||||
|
||||
uint16_t getword286()
|
||||
{
|
||||
uint16_t temp=readmemw(cs,pc); pc+=2;
|
||||
return temp;
|
||||
}
|
||||
|
||||
int ratio1=0,ratio2=0;
|
||||
|
||||
extern uint32_t oldcs2;
|
||||
extern uint32_t oldpc2;
|
||||
|
||||
int indump = 0;
|
||||
|
||||
void dumpregs()
|
||||
{
|
||||
FILE *f;
|
||||
int c,d=0,e=0;
|
||||
int c,d=0,e=0,ff;
|
||||
if (indump) return;
|
||||
indump = 1;
|
||||
// return;
|
||||
output=0;
|
||||
// return;
|
||||
// savenvr();
|
||||
/* printf("The ratio is %i %i\n",ratio1,ratio2);
|
||||
for (c=0;c<256;c++)
|
||||
{
|
||||
printf("ISRAM : %06X %i\n",c<<16,isram[c]);
|
||||
}*/
|
||||
// return;
|
||||
chdir(pcempath);
|
||||
nopageerrors=1;
|
||||
/* f=fopen("rram3.dmp","wb");
|
||||
for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f);
|
||||
fclose(f);*/
|
||||
/* f=fopen("ram.dmp","wb");
|
||||
f=fopen("ram.dmp","wb");
|
||||
fwrite(ram,mem_size*1024*1024,1,f);
|
||||
fclose(f);
|
||||
/* pclog("Dumping rram5.dmp\n");
|
||||
f=fopen("rram5.dmp","wb");
|
||||
for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10150000),f);
|
||||
fclose(f);*/
|
||||
/* f=fopen("rram.dmp","wb");
|
||||
pclog("Dumping rram.dmp\n");
|
||||
f=fopen("rram.dmp","wb");
|
||||
for (c=0;c<0x1000000;c++) putc(readmemb(c),f);
|
||||
fclose(f);
|
||||
f=fopen("rram2.dmp","wb");
|
||||
/* f=fopen("rram2.dmp","wb");
|
||||
for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f);
|
||||
fclose(f);
|
||||
f = fopen("stack.dmp","wb");
|
||||
|
|
@ -623,12 +536,15 @@ chdir(pcempath);
|
|||
f = fopen("tempx2.dmp","wb");
|
||||
for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f);
|
||||
fclose(f);*/
|
||||
/* f=fopen("rram4.dmp","wb");
|
||||
for (c=0;c<0x3000000;c++) putc(readmemb(c+0x80000000),f);
|
||||
fclose(f);*/
|
||||
/* f=fopen("rram5.dmp","wb");
|
||||
for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10000000),f);
|
||||
fclose(f);*/
|
||||
pclog("Dumping rram4.dmp\n");
|
||||
f=fopen("rram4.dmp","wb");
|
||||
for (c=0;c<0x0050000;c++)
|
||||
{
|
||||
abrt = 0;
|
||||
putc(readmemb386l(0,c+0x80000000),f);
|
||||
}
|
||||
fclose(f);
|
||||
pclog("Dumping done\n");
|
||||
/* f=fopen("rram6.dmp","wb");
|
||||
for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f);
|
||||
fclose(f);*/
|
||||
|
|
@ -644,10 +560,10 @@ chdir(pcempath);
|
|||
f=fopen("ram8.bin","wb");
|
||||
fwrite(ram+0x3D210,0x200,1,f);
|
||||
fclose(f); */
|
||||
/* f=fopen("vram.dmp","wb");
|
||||
f=fopen("vram.dmp","wb");
|
||||
fwrite(vram,0x400000,1,f);
|
||||
fclose(f);
|
||||
f=fopen("bios.dmp","wb");
|
||||
/* f=fopen("bios.dmp","wb");
|
||||
fwrite(rom,0x20000,1,f);
|
||||
fclose(f);
|
||||
f=fopen("vbios.dmp","wb");
|
||||
|
|
@ -670,7 +586,7 @@ chdir(pcempath);
|
|||
else
|
||||
printf("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP);
|
||||
printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",pc,CS,DS,ES,SS,flags);
|
||||
printf("%04X:%04X %04X:%04X %08X %08X %08X\n",oldcs,oldpc, oldcs2, oldpc2, old8,old82,old83);
|
||||
printf("%04X:%04X %04X:%04X\n",oldcs,oldpc, oldcs2, oldpc2);
|
||||
printf("%i ins\n",ins);
|
||||
if (is386)
|
||||
printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real");
|
||||
|
|
@ -703,14 +619,28 @@ chdir(pcempath);
|
|||
printf("Entries in readlookup : %i writelookup : %i\n",d,e);
|
||||
d=0;
|
||||
x87_dumpregs();
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
e = -1;
|
||||
for (d = 0; d < 256; d++)
|
||||
{
|
||||
if (inscounts[d] > e)
|
||||
{
|
||||
e = inscounts[d];
|
||||
ff = d;
|
||||
}
|
||||
}
|
||||
inscounts[ff] = -1;
|
||||
// printf("Opcode %02x - %i\n", ff, e);
|
||||
}
|
||||
/* for (c=0;c<1024*1024;c++)
|
||||
{
|
||||
if (mmucache[c]!=0xFFFFFFFF) d++;
|
||||
}
|
||||
printf("Entries in MMU cache : %i\n",d);*/
|
||||
indump = 0;
|
||||
}
|
||||
|
||||
int isAT;
|
||||
int resets = 0;
|
||||
void resetx86()
|
||||
{
|
||||
|
|
@ -733,12 +663,12 @@ void resetx86()
|
|||
resetreadlookup();
|
||||
makemod1table();
|
||||
resetmcr();
|
||||
isAT=AT;
|
||||
FETCHCLEAR();
|
||||
x87_reset();
|
||||
cpu_set_edx();
|
||||
ESP=0;
|
||||
mmu_perm=4;
|
||||
memset(inscounts, 0, sizeof(inscounts));
|
||||
}
|
||||
|
||||
void softresetx86()
|
||||
|
|
@ -759,32 +689,19 @@ void softresetx86()
|
|||
flags=2;
|
||||
}
|
||||
|
||||
#undef AT
|
||||
#define AT isAT
|
||||
|
||||
extern int is486;
|
||||
void setznp8(uint8_t val)
|
||||
static void setznp8(uint8_t val)
|
||||
{
|
||||
flags&=~0xC4;
|
||||
flags|=znptable8[val];
|
||||
}
|
||||
|
||||
#define setznp168 setznp16
|
||||
void setznp16(uint16_t val)
|
||||
static void setznp16(uint16_t val)
|
||||
{
|
||||
flags&=~0xC4;
|
||||
// flags|=((val&0x8000)?N_FLAG:((!val)?Z_FLAG:0));
|
||||
// flags|=(((znptable8[val&0xFF]&P_FLAG)==(znptable8[val>>8]&P_FLAG))?P_FLAG:0);
|
||||
flags|=znptable16[val];
|
||||
}
|
||||
|
||||
/*void setznp168(uint16_t val)
|
||||
{
|
||||
flags&=~0xC4;
|
||||
flags|=(znptable16[val]&0xC0)|(znptable8[val&0xFF]&4);
|
||||
}*/
|
||||
|
||||
void setadd8(uint8_t a, uint8_t b)
|
||||
static void setadd8(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a+(uint16_t)b;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -793,7 +710,7 @@ void setadd8(uint8_t a, uint8_t b)
|
|||
if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG;
|
||||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setadd8nc(uint8_t a, uint8_t b)
|
||||
static void setadd8nc(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a+(uint16_t)b;
|
||||
flags&=~0x8D4;
|
||||
|
|
@ -801,7 +718,7 @@ void setadd8nc(uint8_t a, uint8_t b)
|
|||
if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG;
|
||||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setadc8(uint8_t a, uint8_t b)
|
||||
static void setadc8(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a+(uint16_t)b+tempc;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -810,7 +727,7 @@ void setadc8(uint8_t a, uint8_t b)
|
|||
if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG;
|
||||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setadd16(uint16_t a, uint16_t b)
|
||||
static void setadd16(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a+(uint32_t)b;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -819,7 +736,7 @@ void setadd16(uint16_t a, uint16_t b)
|
|||
if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG;
|
||||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setadd16nc(uint16_t a, uint16_t b)
|
||||
static void setadd16nc(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a+(uint32_t)b;
|
||||
flags&=~0x8D4;
|
||||
|
|
@ -827,7 +744,7 @@ void setadd16nc(uint16_t a, uint16_t b)
|
|||
if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG;
|
||||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setadc16(uint16_t a, uint16_t b)
|
||||
static void setadc16(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a+(uint32_t)b+tempc;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -837,7 +754,7 @@ void setadc16(uint16_t a, uint16_t b)
|
|||
if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
|
||||
void setsub8(uint8_t a, uint8_t b)
|
||||
static void setsub8(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a-(uint16_t)b;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -846,7 +763,7 @@ void setsub8(uint8_t a, uint8_t b)
|
|||
if ((a^b)&(a^c)&0x80) flags|=V_FLAG;
|
||||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setsub8nc(uint8_t a, uint8_t b)
|
||||
static void setsub8nc(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a-(uint16_t)b;
|
||||
flags&=~0x8D4;
|
||||
|
|
@ -854,7 +771,7 @@ void setsub8nc(uint8_t a, uint8_t b)
|
|||
if ((a^b)&(a^c)&0x80) flags|=V_FLAG;
|
||||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setsbc8(uint8_t a, uint8_t b)
|
||||
static void setsbc8(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc);
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -863,7 +780,7 @@ void setsbc8(uint8_t a, uint8_t b)
|
|||
if ((a^b)&(a^c)&0x80) flags|=V_FLAG;
|
||||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setsub16(uint16_t a, uint16_t b)
|
||||
static void setsub16(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a-(uint32_t)b;
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -873,7 +790,7 @@ void setsub16(uint16_t a, uint16_t b)
|
|||
// if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG);
|
||||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setsub16nc(uint16_t a, uint16_t b)
|
||||
static void setsub16nc(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a-(uint32_t)b;
|
||||
flags&=~0x8D4;
|
||||
|
|
@ -882,7 +799,7 @@ void setsub16nc(uint16_t a, uint16_t b)
|
|||
if ((a^b)&(a^c)&0x8000) flags|=V_FLAG;
|
||||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
void setsbc16(uint16_t a, uint16_t b)
|
||||
static void setsbc16(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc);
|
||||
flags&=~0x8D5;
|
||||
|
|
@ -893,107 +810,31 @@ void setsbc16(uint16_t a, uint16_t b)
|
|||
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
|
||||
}
|
||||
|
||||
|
||||
int totaldiff = 0;
|
||||
int current_diff = 0;
|
||||
void clockhardware()
|
||||
{
|
||||
cycdiff-=cycles;
|
||||
|
||||
keybsenddelay--;
|
||||
if (keybsenddelay<1)
|
||||
{
|
||||
keybsenddelay = 1000;//2500;
|
||||
keyboard_poll();
|
||||
}
|
||||
|
||||
pit.c[0]-=cycdiff;
|
||||
pit.c[1]-=cycdiff;
|
||||
if (ppi.pb&1) pit.c[2]-=cycdiff;
|
||||
|
||||
if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll();
|
||||
|
||||
spktime-=cycdiff;
|
||||
if (spktime<=0.0)
|
||||
{
|
||||
spktime+=SPKCONST;
|
||||
pollspk();
|
||||
pollgussamp();
|
||||
getsbsamp();
|
||||
getdacsamp();
|
||||
polladlib();
|
||||
}
|
||||
soundtime-=cycdiff;
|
||||
if (soundtime<=0.0)
|
||||
{
|
||||
soundtime+=SOUNDCONST;
|
||||
pollsound60hz();
|
||||
}
|
||||
gustime-=cycdiff;
|
||||
while (gustime<=0.0)
|
||||
{
|
||||
gustime+=GUSCONST;
|
||||
// printf("1Poll GUS %f %f\n",gustime,GUSCONST);
|
||||
pollgus();
|
||||
// printf("2Poll GUS\n");
|
||||
}
|
||||
vidtime-=cycdiff;
|
||||
if (vidtime<=0.0)
|
||||
{
|
||||
pollvideo();
|
||||
// polltandy();
|
||||
// pollmda();
|
||||
// pollcga();
|
||||
}
|
||||
if (disctime)
|
||||
{
|
||||
disctime-=(cycdiff/2);
|
||||
if (disctime<=0)
|
||||
{
|
||||
disctime=0;
|
||||
fdc_poll();
|
||||
}
|
||||
}
|
||||
if (mousedelay)
|
||||
{
|
||||
mousedelay--;
|
||||
if (!mousedelay)
|
||||
mousecallback();
|
||||
}
|
||||
if (sbenable)
|
||||
{
|
||||
sbcount-=cycdiff;
|
||||
if (sbcount<0)
|
||||
{
|
||||
sbcount+=sblatcho;
|
||||
pollsb();
|
||||
}
|
||||
}
|
||||
rtctime-=cycdiff;
|
||||
if (rtctime<0)
|
||||
{
|
||||
nvr_rtc();
|
||||
}
|
||||
cycdiff=cycles;
|
||||
if (idecallback[0])
|
||||
{
|
||||
idecallback[0]--;
|
||||
if (idecallback[0]<=0)
|
||||
{
|
||||
// pclog("IDE time over\n");
|
||||
idecallback[0]=0;
|
||||
callbackide(0);
|
||||
}
|
||||
}
|
||||
int diff = cycdiff - cycles - current_diff;
|
||||
|
||||
current_diff += diff;
|
||||
totaldiff += diff;
|
||||
pit.c[0] -= diff;
|
||||
pit.c[1] -= diff;
|
||||
if (ppi.pb & 1) pit.c[2] -= diff;
|
||||
if ((pit.c[0] < 1) || (pit.c[1] < 1) || (pit.c[2] < 1)) pit_poll();
|
||||
|
||||
timer_clock(diff);
|
||||
}
|
||||
|
||||
|
||||
int firstrepcycle=1;
|
||||
void cpu_writeport(uint32_t port, uint8_t val) { outb(port,val); }
|
||||
int firstrepcycle=1;
|
||||
|
||||
void rep(int fv)
|
||||
{
|
||||
uint8_t temp;
|
||||
int c=CX;
|
||||
uint8_t temp2;
|
||||
uint16_t tempw,tempw2,tempw3;
|
||||
uint16_t tempw,tempw2;
|
||||
uint16_t ipc=oldpc;//pc-1;
|
||||
int changeds=0;
|
||||
uint32_t oldds;
|
||||
|
|
@ -1051,9 +892,9 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) { DI--; SI--; }
|
||||
else { DI++; SI++; }
|
||||
c--;
|
||||
cycles-=((AT)?4:17);
|
||||
cycles-=17;
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?4:17)-memcycs);
|
||||
FETCHADD(17-memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0) pc=ipc;
|
||||
// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1069,9 +910,9 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) { DI-=2; SI-=2; }
|
||||
else { DI+=2; SI+=2; }
|
||||
c--;
|
||||
cycles-=((AT)?4:17);
|
||||
cycles-=17;
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?4:17)-memcycs);
|
||||
FETCHADD(17 - memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0) pc=ipc;
|
||||
// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1090,11 +931,10 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) { DI--; SI--; }
|
||||
else { DI++; SI++; }
|
||||
c--;
|
||||
if (!AT) cycles-=30;
|
||||
else cycles-=9;
|
||||
cycles -= 30;
|
||||
setsub8(temp,temp2);
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?9:30)-memcycs);
|
||||
FETCHADD(30 - memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc;
|
||||
// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1111,11 +951,10 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) { DI-=2; SI-=2; }
|
||||
else { DI+=2; SI+=2; }
|
||||
c--;
|
||||
if (!AT) cycles-=30;
|
||||
else cycles-=9;
|
||||
cycles -= 30;
|
||||
setsub16(tempw,tempw2);
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?9:30)-memcycs);
|
||||
FETCHADD(30 - memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc;
|
||||
// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1130,9 +969,9 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) DI--;
|
||||
else DI++;
|
||||
c--;
|
||||
cycles-=((AT)?3:10);
|
||||
cycles -= 10;
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?3:10)-memcycs);
|
||||
FETCHADD(10 - memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0) pc=ipc;
|
||||
// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1146,14 +985,13 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) DI-=2;
|
||||
else DI+=2;
|
||||
c--;
|
||||
cycles-=((AT)?3:10);
|
||||
cycles -= 10;
|
||||
clockhardware();
|
||||
FETCHADD(((AT)?3:10)-memcycs);
|
||||
FETCHADD(10 - memcycs);
|
||||
}
|
||||
if (IRQTEST && c>0) pc=ipc;
|
||||
// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
// else firstrepcycle=1;
|
||||
// printf("REP STOSW %04X:%04X %04X:%04X %04X %04X\n",CS,pc,ES,DI,AX,CX); }
|
||||
break;
|
||||
case 0xAC: /*REP LODSB*/
|
||||
if (c>0)
|
||||
|
|
@ -1191,7 +1029,7 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) DI--;
|
||||
else DI++;
|
||||
c--;
|
||||
cycles-=((AT)?8:15);
|
||||
cycles -= 15;
|
||||
}
|
||||
//if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0))));
|
||||
if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
|
|
@ -1208,7 +1046,7 @@ void rep(int fv)
|
|||
if (flags&D_FLAG) DI-=2;
|
||||
else DI+=2;
|
||||
c--;
|
||||
cycles-=((AT)?8:15);
|
||||
cycles -= 15;
|
||||
}
|
||||
if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); }
|
||||
else firstrepcycle=1;
|
||||
|
|
@ -1233,7 +1071,7 @@ int firstrepcycle;
|
|||
int skipnextprint=0;
|
||||
|
||||
|
||||
int instime=0,instimer=0;
|
||||
int instime=0;
|
||||
//#if 0
|
||||
void execx86(int cycs)
|
||||
{
|
||||
|
|
@ -1245,7 +1083,7 @@ void execx86(int cycs)
|
|||
int c;
|
||||
int tempi;
|
||||
int trap;
|
||||
FILE *f;
|
||||
|
||||
// printf("Run x86! %i %i\n",cycles,cycs);
|
||||
cycles+=cycs;
|
||||
// i86_Execute(cycs);
|
||||
|
|
@ -1258,6 +1096,7 @@ void execx86(int cycs)
|
|||
// if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; }
|
||||
// if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime);
|
||||
cycdiff=cycles;
|
||||
current_diff = 0;
|
||||
cycles-=nextcyc;
|
||||
// if (instime) pclog("Cycles %i %i\n",cycles,cycdiff);
|
||||
nextcyc=0;
|
||||
|
|
@ -1273,14 +1112,14 @@ void execx86(int cycs)
|
|||
// output=1;
|
||||
// if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat);
|
||||
//#if 0
|
||||
if (output && /*cs<0xF0000 && */!ssegs && (pc<0x43A || pc>0x44A))//opcode!=0x26 && opcode!=0x36 && opcode!=0x2E && opcode!=0x3E)
|
||||
if (output)
|
||||
{
|
||||
if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle)
|
||||
{
|
||||
// if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle)
|
||||
// {
|
||||
if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %02X %02X %02X %02X\n",cs,pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ram[0x413], ram[0x414], ram[0x415], ram[0x416]);
|
||||
skipnextprint=0;
|
||||
// ins++;
|
||||
}
|
||||
// }
|
||||
}
|
||||
//#endif
|
||||
pc++;
|
||||
|
|
@ -2549,74 +2388,24 @@ void execx86(int cycs)
|
|||
lastcs=CS;
|
||||
temp=FETCH();
|
||||
|
||||
// if (temp == 0x13 && AX == 0x0201 && ES == 0x0BF5 && CX == 0x1D06) output = 3;
|
||||
// if (temp==0x10 && !AH) printf("Entering mode %02X\n",AL);
|
||||
// if (temp==0x18 || temp==0x19) { printf("INT %02X\n",temp); output=1; }
|
||||
// /*if (temp==0x13) */printf("INT %02X %04X %04X:%04X %04X %04X:%04X %04X:%04X\n",temp,AX,ES,BX,CX,DS,DX,CS,pc);
|
||||
//if (temp == 0x13 && AH == 2) output = 3;
|
||||
/* if (CS==0xC800 && temp==0x13)
|
||||
{
|
||||
output=3;
|
||||
timetolive=100000;
|
||||
}*/
|
||||
/* if (temp==0x10) printf("INT 10 %04X %04X %04X %04X %04X:%04X %06X %06X %c\n",AX,BX,CX,DX,cs>>4,pc,ds,ds+DX, (AL > 31) ? AL : '.');
|
||||
if (temp == 0x10 && AX == 0xe35)
|
||||
{
|
||||
dumpregs();
|
||||
if (ssegs) ss=oldss;
|
||||
writememw(ss,((SP-2)&0xFFFF),flags|0xF000);
|
||||
writememw(ss,((SP-4)&0xFFFF),CS);
|
||||
writememw(ss,((SP-6)&0xFFFF),pc);
|
||||
flags&=~T_FLAG;
|
||||
SP-=6;
|
||||
addr=temp<<2;
|
||||
pc=readmemw(0,addr);
|
||||
|
||||
loadcs(readmemw(0,addr+2));
|
||||
FETCHCLEAR();
|
||||
|
||||
}*/
|
||||
/* if (temp==0x21 && AH==9)
|
||||
{
|
||||
addr=0;
|
||||
while (ram[ds+DX+addr]!='$')
|
||||
{
|
||||
printf("%c",ram[ds+DX+addr]);
|
||||
addr++;
|
||||
}
|
||||
printf("\n");
|
||||
printf("Called from %04X\n",readmemw(ss,SP));
|
||||
}*/
|
||||
// output=0;
|
||||
// if (temp==0x13 && AH==3) printf("Write sector %04X:%04X %05X\n",es>>4,BX,es+BX);
|
||||
/* if (temp==0x13 && (DL==0x80 || DL==0x81) && AH>0)
|
||||
{
|
||||
int13hdc();
|
||||
}
|
||||
else *//*if (temp==0x13 && AH==2 && DL<2)// && FASTDISC)
|
||||
{
|
||||
int13read();
|
||||
//output=1;
|
||||
}
|
||||
else if (temp==0x13 && AH==3 && DL<2)// && FASTDISC)
|
||||
{
|
||||
int13write();
|
||||
}
|
||||
else if (temp==0x13 && AH==4 && DL<2)// && FASTDISC)
|
||||
{
|
||||
AH=0;
|
||||
flags&=~C_FLAG;
|
||||
}
|
||||
else
|
||||
{*/
|
||||
if (ssegs) ss=oldss;
|
||||
writememw(ss,((SP-2)&0xFFFF),flags|0xF000);
|
||||
writememw(ss,((SP-4)&0xFFFF),CS);
|
||||
writememw(ss,((SP-6)&0xFFFF),pc);
|
||||
flags&=~T_FLAG;
|
||||
SP-=6;
|
||||
addr=temp<<2;
|
||||
pc=readmemw(0,addr);
|
||||
// printf("CD\n");
|
||||
loadcs(readmemw(0,addr+2));
|
||||
FETCHCLEAR();
|
||||
// }
|
||||
cycles-=71;
|
||||
break;
|
||||
case 0xCF: /*IRET*/
|
||||
if (ssegs) ss=oldss;
|
||||
tempw=CS;
|
||||
tempw2=pc;
|
||||
inint=0;
|
||||
pc=readmemw(ss,SP);
|
||||
// printf("CF\n");
|
||||
loadcs(readmemw(ss,((SP+2)&0xFFFF)));
|
||||
|
|
@ -3063,14 +2852,14 @@ void execx86(int cycs)
|
|||
tempws=FETCH();
|
||||
AH=AL/tempws;
|
||||
AL%=tempws;
|
||||
setznp168(AX);
|
||||
setznp16(AX);
|
||||
cycles-=83;
|
||||
break;
|
||||
case 0xD5: /*AAD*/
|
||||
tempws=FETCH();
|
||||
AL=(AH*tempws)+AL;
|
||||
AH=0;
|
||||
setznp168(AX);
|
||||
setznp16(AX);
|
||||
cycles-=60;
|
||||
break;
|
||||
case 0xD7: /*XLAT*/
|
||||
|
|
@ -3669,7 +3458,6 @@ void execx86(int cycs)
|
|||
// printf("INT INT INT\n");
|
||||
loadcs(readmemw(0,addr+2));
|
||||
FETCHCLEAR();
|
||||
inint=1;
|
||||
// printf("INTERRUPT\n");
|
||||
}
|
||||
}
|
||||
187
src/adlib.c
187
src/adlib.c
|
|
@ -1,187 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "mame/fmopl.h"
|
||||
#include "mame/ymf262.h"
|
||||
|
||||
/*Interfaces between PCem and the actual Adlib emulator*/
|
||||
|
||||
static int adlib_inited = 0;
|
||||
int adlibpos=0;
|
||||
void *YM3812[2];
|
||||
void *YMF262;
|
||||
int fm_timers[2][2],fm_timers_enable[2][2];
|
||||
|
||||
void adlib_write(uint16_t a, uint8_t v)
|
||||
{
|
||||
// printf("Adlib write %04X %02X %i\n",a,v,sbtype);
|
||||
if (!sbtype) return;
|
||||
if (sbtype<SBPRO && a<0x224) return;
|
||||
switch (a)
|
||||
{
|
||||
case 0x220: case 0x221:
|
||||
if (sbtype<SBPRO2) ym3812_write(YM3812[0],a,v);
|
||||
else ymf262_write(YMF262,a,v);
|
||||
break;
|
||||
case 0x222: case 0x223:
|
||||
if (sbtype<SBPRO2) ym3812_write(YM3812[1],a,v);
|
||||
else ymf262_write(YMF262,a,v);
|
||||
break;
|
||||
case 0x228: case 0x229: case 0x388: case 0x389:
|
||||
if (sbtype<SBPRO2)
|
||||
{
|
||||
ym3812_write(YM3812[0],a,v);
|
||||
ym3812_write(YM3812[1],a,v);
|
||||
}
|
||||
else
|
||||
ymf262_write(YMF262,a,v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t adlib_read(uint16_t a)
|
||||
{
|
||||
uint8_t temp;
|
||||
// printf("Adlib read %04X\n",a);
|
||||
if (sbtype>=SBPRO2)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case 0x220: case 0x221:
|
||||
case 0x222: case 0x223:
|
||||
case 0x228: case 0x229:
|
||||
case 0x388: case 0x389:
|
||||
temp=ymf262_read(YMF262,a);
|
||||
// pclog("YMF262 read %03X %02X\n",a,temp);
|
||||
cycles-=(int)(isa_timing * 8);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
if (!sbtype) return 0xFF;
|
||||
switch (a)
|
||||
{
|
||||
case 0x220: case 0x221:
|
||||
if (sbtype<SBPRO) return 0xFF;
|
||||
case 0x228: case 0x229:
|
||||
case 0x388: case 0x389:
|
||||
cycles-=(int)(isa_timing * 8);
|
||||
return ym3812_read(YM3812[0],a);
|
||||
case 0x222: case 0x223:
|
||||
if (sbtype<SBPRO) return 0xFF;
|
||||
return ym3812_read(YM3812[1],a);
|
||||
}
|
||||
/* if (sbtype<SBPRO && a<0x224) return 0xFF;
|
||||
if (a==0x222) return adlibstat2;
|
||||
if (!(a&1)) return adlibstat;
|
||||
return 0;*/
|
||||
}
|
||||
|
||||
signed short *ad_bufs[4];
|
||||
int16_t ad_filtbuf[2]={0,0};
|
||||
void getadlib(signed short *bufl, signed short *bufr, int size)
|
||||
{
|
||||
int c;
|
||||
if (sbtype>=SBPRO2)
|
||||
{
|
||||
ymf262_update_one(YMF262,ad_bufs,size);
|
||||
for (c=0;c<size;c++)
|
||||
{
|
||||
ad_filtbuf[0]=bufl[c]=(ad_bufs[0][c]/4)+((ad_filtbuf[0]*11)/16);
|
||||
ad_filtbuf[1]=bufr[c]=(ad_bufs[1][c]/4)+((ad_filtbuf[1]*11)/16);
|
||||
}
|
||||
if (fm_timers_enable[0][0])
|
||||
{
|
||||
fm_timers[0][0]--;
|
||||
if (fm_timers[0][0]<0) ymf262_timer_over(YMF262,0);
|
||||
}
|
||||
if (fm_timers_enable[0][1])
|
||||
{
|
||||
fm_timers[0][1]--;
|
||||
if (fm_timers[0][1]<0) ymf262_timer_over(YMF262,1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ym3812_update_one(YM3812[0],bufl,size);
|
||||
ym3812_update_one(YM3812[1],bufr,size);
|
||||
for (c=0;c<size;c++)
|
||||
{
|
||||
ad_filtbuf[0]=bufl[c]=(bufl[c]/4)+((ad_filtbuf[0]*11)/16);
|
||||
ad_filtbuf[1]=bufr[c]=(bufr[c]/4)+((ad_filtbuf[1]*11)/16);
|
||||
}
|
||||
if (fm_timers_enable[0][0])
|
||||
{
|
||||
fm_timers[0][0]--;
|
||||
if (fm_timers[0][0]<0) ym3812_timer_over(YM3812[0],0);
|
||||
}
|
||||
if (fm_timers_enable[0][1])
|
||||
{
|
||||
fm_timers[0][1]--;
|
||||
if (fm_timers[0][1]<0) ym3812_timer_over(YM3812[0],1);
|
||||
}
|
||||
if (fm_timers_enable[1][0])
|
||||
{
|
||||
fm_timers[1][0]--;
|
||||
if (fm_timers[1][0]<0) ym3812_timer_over(YM3812[1],0);
|
||||
}
|
||||
if (fm_timers_enable[1][1])
|
||||
{
|
||||
fm_timers[1][1]--;
|
||||
if (fm_timers[1][1]<0) ym3812_timer_over(YM3812[1],1);
|
||||
}
|
||||
}
|
||||
// for (c=0;c<size;c++) buf[c]/=2;
|
||||
}
|
||||
|
||||
void ym3812_timer_set_0(void *param,int timer,attotime period)
|
||||
{
|
||||
fm_timers[0][timer]=period/20833;
|
||||
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
|
||||
fm_timers_enable[0][timer]=(period)?1:0;
|
||||
}
|
||||
void ym3812_timer_set_1(void *param,int timer,attotime period)
|
||||
{
|
||||
fm_timers[1][timer]=period/20833;
|
||||
if (!fm_timers[1][timer]) fm_timers[1][timer]=1;
|
||||
fm_timers_enable[1][timer]=(period)?1:0;
|
||||
}
|
||||
|
||||
void ymf262_timer_set(void *param,int timer,attotime period)
|
||||
{
|
||||
fm_timers[0][timer]=period/20833;
|
||||
if (!fm_timers[0][timer]) fm_timers[0][timer]=1;
|
||||
fm_timers_enable[0][timer]=(period)?1:0;
|
||||
}
|
||||
|
||||
void adlib_init()
|
||||
{
|
||||
if (!adlib_inited)
|
||||
{
|
||||
ad_bufs[0]=(signed short *)malloc(48000);
|
||||
ad_bufs[1]=(signed short *)malloc(48000);
|
||||
ad_bufs[2]=(signed short *)malloc(48000);
|
||||
ad_bufs[3]=(signed short *)malloc(48000);
|
||||
|
||||
YM3812[0]=ym3812_init((void *)NULL,3579545,48000);
|
||||
ym3812_reset_chip(YM3812[0]);
|
||||
ym3812_set_timer_handler(YM3812[0],ym3812_timer_set_0,NULL);
|
||||
YM3812[1]=ym3812_init((void *)NULL,3579545,48000);
|
||||
ym3812_reset_chip(YM3812[1]);
|
||||
ym3812_set_timer_handler(YM3812[1],ym3812_timer_set_1,NULL);
|
||||
|
||||
YMF262=ymf262_init((void *)NULL,3579545*4,48000);
|
||||
ymf262_reset_chip(YMF262);
|
||||
ymf262_set_timer_handler(YMF262,ymf262_timer_set,NULL);
|
||||
}
|
||||
|
||||
adlib_inited = 1;
|
||||
|
||||
io_sethandler(0x0388, 0x0002, adlib_read, NULL, NULL, adlib_write, NULL, NULL);
|
||||
}
|
||||
|
||||
void adlib_reset()
|
||||
{
|
||||
ym3812_reset_chip(YM3812[0]);
|
||||
ym3812_reset_chip(YM3812[1]);
|
||||
ymf262_reset_chip(YMF262);
|
||||
}
|
||||
141
src/cms.c
141
src/cms.c
|
|
@ -1,141 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "ibm.h"
|
||||
|
||||
int cmsaddrs[2];
|
||||
uint8_t cmsregs[2][32];
|
||||
uint16_t cmslatch[12],cmsnoisefreq[12];
|
||||
int cmsfreq[12];
|
||||
float cmscount[12];
|
||||
int cmsvol[12][2];
|
||||
int cmsstat[12];
|
||||
uint16_t cmsnoise[4];
|
||||
int cmsnoisecount[4];
|
||||
int cmsnoisetype[4];
|
||||
|
||||
#define CMSCONST (62500.0/44100.0)
|
||||
|
||||
void getcms(signed short *p, int size)
|
||||
{
|
||||
int c,d;
|
||||
int ena[12],noiseena[12];
|
||||
for (c=0;c<6;c++)
|
||||
{
|
||||
ena[c]=(cmsregs[0][0x14]&(1<<c));
|
||||
ena[c+6]=(cmsregs[1][0x14]&(1<<c));
|
||||
}
|
||||
if (!(cmsregs[0][0x1C]&1))
|
||||
{
|
||||
for (c=0;c<6;c++) ena[c]=0;
|
||||
}
|
||||
if (!(cmsregs[1][0x1C]&1))
|
||||
{
|
||||
for (c=0;c<6;c++) ena[c+6]=0;
|
||||
}
|
||||
for (c=0;c<6;c++)
|
||||
{
|
||||
noiseena[c]=(cmsregs[0][0x15]&(1<<c));
|
||||
noiseena[c+6]=(cmsregs[1][0x15]&(1<<c));
|
||||
}
|
||||
if (!(cmsregs[0][0x1C]&1))
|
||||
{
|
||||
for (c=0;c<6;c++) noiseena[c]=0;
|
||||
}
|
||||
if (!(cmsregs[1][0x1C]&1))
|
||||
{
|
||||
for (c=0;c<6;c++) noiseena[c+6]=0;
|
||||
}
|
||||
for (c=0;c<4;c++)
|
||||
{
|
||||
switch (cmsnoisetype[c])
|
||||
{
|
||||
case 0: cmsnoisefreq[c]=31250; break;
|
||||
case 1: cmsnoisefreq[c]=15625; break;
|
||||
case 2: cmsnoisefreq[c]=7812; break;
|
||||
case 3: cmsnoisefreq[c]=cmsfreq[c*3]; break;
|
||||
}
|
||||
}
|
||||
for (c=0;c<(size<<1);c+=2)
|
||||
{
|
||||
p[c]=0;
|
||||
p[c+1]=0;
|
||||
for (d=0;d<12;d++)
|
||||
{
|
||||
if (ena[d])
|
||||
{
|
||||
if (cmsstat[d]) p[c] +=(cmsvol[d][0]*90);
|
||||
if (cmsstat[d]) p[c+1]+=(cmsvol[d][1]*90);
|
||||
cmscount[d]+=cmsfreq[d];
|
||||
if (cmscount[d]>=(22050))
|
||||
{
|
||||
cmscount[d]-=(22050);
|
||||
cmsstat[d]^=1;
|
||||
}
|
||||
}
|
||||
else if (noiseena[d])
|
||||
{
|
||||
if (cmsnoise[d/3]&1) p[c] +=(cmsvol[d][0]*90);
|
||||
if (cmsnoise[d/3]&1) p[c+1]+=(cmsvol[d][0]*90);
|
||||
}
|
||||
}
|
||||
for (d=0;d<4;d++)
|
||||
{
|
||||
cmsnoisecount[d]+=cmsnoisefreq[d];
|
||||
while (cmsnoisecount[d]>=22050)
|
||||
{
|
||||
cmsnoisecount[d]-=22050;
|
||||
cmsnoise[d]<<=1;
|
||||
if (!(((cmsnoise[d]&0x4000)>>8)^(cmsnoise[d]&0x40))) cmsnoise[d]|=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writecms(uint16_t addr, uint8_t val)
|
||||
{
|
||||
int voice;
|
||||
int chip=(addr&2)>>1;
|
||||
if (addr&1)
|
||||
cmsaddrs[chip]=val&31;
|
||||
else
|
||||
{
|
||||
cmsregs[chip][cmsaddrs[chip]&31]=val;
|
||||
switch (cmsaddrs[chip]&31)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: /*Volume*/
|
||||
case 0x03: case 0x04: case 0x05:
|
||||
voice=cmsaddrs[chip]&7;
|
||||
if (chip) voice+=6;
|
||||
cmsvol[voice][0]=val&0xF;//((val&0xF)+(val>>4))>>1;
|
||||
cmsvol[voice][1]=val>>4;
|
||||
break;
|
||||
case 0x08: case 0x09: case 0x0A: /*Frequency*/
|
||||
case 0x0B: case 0x0C: case 0x0D:
|
||||
voice=cmsaddrs[chip]&7;
|
||||
if (chip) voice+=6;
|
||||
cmslatch[voice]=(cmslatch[voice]&0x700)|val;
|
||||
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
|
||||
break;
|
||||
case 0x10: case 0x11: case 0x12: /*Octave*/
|
||||
voice=(cmsaddrs[chip]&3)<<1;
|
||||
if (chip) voice+=6;
|
||||
cmslatch[voice]=(cmslatch[voice]&0xFF)|((val&7)<<8);
|
||||
cmslatch[voice+1]=(cmslatch[voice+1]&0xFF)|((val&0x70)<<4);
|
||||
cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255));
|
||||
cmsfreq[voice+1]=(15625<<(cmslatch[voice+1]>>8))/(511-(cmslatch[voice+1]&255));
|
||||
break;
|
||||
case 0x16: /*Noise*/
|
||||
voice=chip*2;
|
||||
cmsnoisetype[voice]=val&3;
|
||||
cmsnoisetype[voice+1]=(val>>4)&3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readcms(uint16_t addr)
|
||||
{
|
||||
int chip=(addr&2)>>1;
|
||||
if (addr&1) return cmsaddrs[chip];
|
||||
return cmsregs[chip][cmsaddrs[chip]&31];
|
||||
}
|
||||
|
||||
59
src/device.c
Normal file
59
src/device.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
|
||||
static void *device_priv[256];
|
||||
static device_t *devices[256];
|
||||
|
||||
void device_init()
|
||||
{
|
||||
memset(devices, 0, sizeof(devices));
|
||||
}
|
||||
|
||||
void device_add(device_t *d)
|
||||
{
|
||||
int c = 0;
|
||||
void *priv;
|
||||
|
||||
while (devices[c] != NULL && c < 256)
|
||||
c++;
|
||||
|
||||
if (c >= 256)
|
||||
fatal("device_add : too many devices\n");
|
||||
|
||||
priv = d->init();
|
||||
if (priv == NULL)
|
||||
fatal("device_add : device init failed\n");
|
||||
|
||||
devices[c] = d;
|
||||
device_priv[c] = priv;
|
||||
}
|
||||
|
||||
void device_close_all()
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
if (devices[c] != NULL)
|
||||
{
|
||||
devices[c]->close(device_priv[c]);
|
||||
devices[c] = device_priv[c] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void device_speed_changed()
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
if (devices[c] != NULL)
|
||||
{
|
||||
if (devices[c]->speed_changed != NULL)
|
||||
{
|
||||
devices[c]->speed_changed(device_priv[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/device.h
Normal file
12
src/device.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
typedef struct device_t
|
||||
{
|
||||
char name[50];
|
||||
void *(*init)();
|
||||
void (*close)(void *priv);
|
||||
void (*speed_changed)(void *priv);
|
||||
} device_t;
|
||||
|
||||
void device_init();
|
||||
void device_add(device_t *d);
|
||||
void device_close_all();
|
||||
void device_speed_changed();
|
||||
625
src/gus.c
625
src/gus.c
|
|
@ -1,625 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ibm.h"
|
||||
|
||||
extern int ins;
|
||||
extern int timetolive;
|
||||
int output;
|
||||
//#define GUSRATECONST (44100.0/48000.0)
|
||||
uint8_t *gusram;
|
||||
|
||||
struct
|
||||
{
|
||||
int global;
|
||||
uint32_t addr,dmaaddr;
|
||||
int voice;
|
||||
uint32_t start[32],end[32],cur[32];
|
||||
uint32_t startx[32],endx[32],curx[32];
|
||||
uint32_t rstart[32],rend[32],rcur[32];
|
||||
uint16_t freq[32];
|
||||
uint16_t rfreq[32];
|
||||
uint8_t ctrl[32];
|
||||
uint8_t rctrl[32];
|
||||
int curvol[32];
|
||||
int t1on,t2on;
|
||||
uint8_t tctrl;
|
||||
uint16_t t1,t2,t1l,t2l;
|
||||
uint8_t irqstatus,irqstatus2;
|
||||
uint8_t adcommand;
|
||||
int waveirqs[32],rampirqs[32];
|
||||
int voices;
|
||||
uint8_t dmactrl;
|
||||
} gus;
|
||||
|
||||
double vol16bit[4096];
|
||||
|
||||
void initgus()
|
||||
{
|
||||
int c;
|
||||
for (c=0;c<32;c++)
|
||||
{
|
||||
gus.ctrl[c]=1;
|
||||
gus.rctrl[c]=1;
|
||||
gus.rfreq[c]=63*512;
|
||||
}
|
||||
gusram=malloc(1024*1024);
|
||||
|
||||
double out = 1.0;
|
||||
for (c=4095;c>=0;c--) {
|
||||
vol16bit[c]=out;//(float)c/4095.0;//out;
|
||||
out/=1.002709201; /* 0.0235 dB Steps */
|
||||
}
|
||||
|
||||
printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
|
||||
gus.voices=14;
|
||||
|
||||
}
|
||||
|
||||
void dumpgus()
|
||||
{
|
||||
/* FILE *f=fopen("gusram.dmp","wb");
|
||||
fwrite(gusram,1024*1024,1,f);
|
||||
fclose(f);*/
|
||||
}
|
||||
|
||||
void pollgusirqs()
|
||||
{
|
||||
int c;
|
||||
gus.irqstatus&=~0x60;
|
||||
for (c=0;c<32;c++)
|
||||
{
|
||||
if (gus.waveirqs[c])
|
||||
{
|
||||
// gus.waveirqs[c]=0;
|
||||
gus.irqstatus2=0x60|c;
|
||||
gus.irqstatus|=0x20;
|
||||
// printf("Voice IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
|
||||
picintlevel(0x20);
|
||||
// output=3;
|
||||
// timetolive=5000;
|
||||
return;
|
||||
}
|
||||
if (gus.rampirqs[c])
|
||||
{
|
||||
// gus.rampirqs[c]=0;
|
||||
gus.irqstatus2=0xA0|c;
|
||||
gus.irqstatus|=0x40;
|
||||
// printf("Ramp IRQ %i %02X %i\n",c,gus.irqstatus2,ins);
|
||||
picintlevel(0x20);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gus.irqstatus2=0xE0;
|
||||
// gus.irqstatus&=~0x20;
|
||||
if (!gus.irqstatus) picintc(0x20);
|
||||
}
|
||||
|
||||
int gusirqnext=0;
|
||||
|
||||
void writegus(uint16_t addr, uint8_t val)
|
||||
{
|
||||
int c,d;
|
||||
// printf("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc);
|
||||
switch (addr)
|
||||
{
|
||||
case 0x342: /*Voice select*/
|
||||
gus.voice=val&31;
|
||||
break;
|
||||
case 0x343: /*Global select*/
|
||||
gus.global=val;
|
||||
break;
|
||||
case 0x344: /*Global low*/
|
||||
// if (gus.global!=0x43 && gus.global!=0x44) printf("Writing register %02X %02X %02X\n",gus.global,gus.voice,val);
|
||||
switch (gus.global)
|
||||
{
|
||||
case 0: /*Voice control*/
|
||||
// if (val&1 && !(gus.ctrl[gus.voice]&1)) printf("Voice on %i\n",gus.voice);
|
||||
gus.ctrl[gus.voice]=val;
|
||||
break;
|
||||
case 1: /*Frequency control*/
|
||||
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF00)|val;
|
||||
break;
|
||||
case 2: /*Start addr high*/
|
||||
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xF807F)|(val<<7);
|
||||
gus.start[gus.voice]=(gus.start[gus.voice]&0x1F00FFFF)|(val<<16);
|
||||
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
|
||||
break;
|
||||
case 3: /*Start addr low*/
|
||||
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFFFF00)|val;
|
||||
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
|
||||
break;
|
||||
case 4: /*End addr high*/
|
||||
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xF807F)|(val<<7);
|
||||
gus.end[gus.voice]=(gus.end[gus.voice]&0x1F00FFFF)|(val<<16);
|
||||
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
|
||||
break;
|
||||
case 5: /*End addr low*/
|
||||
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFFFF00)|val;
|
||||
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
|
||||
break;
|
||||
|
||||
case 0x6: /*Ramp frequency*/
|
||||
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
|
||||
// printf("RFREQ %02X %i %i %f\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))));
|
||||
break;
|
||||
|
||||
case 0x9: /*Current volume*/
|
||||
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE0000)|(val<<9);
|
||||
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
|
||||
break;
|
||||
|
||||
case 0xA: /*Current addr high*/
|
||||
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1F00FFFF)|(val<<16);
|
||||
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xF807F00)|((val<<7)<<8);
|
||||
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0F807F00)|((val<<7)<<8);
|
||||
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
|
||||
break;
|
||||
case 0xB: /*Current addr low*/
|
||||
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFFFF00)|val;
|
||||
// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
|
||||
break;
|
||||
|
||||
case 0x42: /*DMA address low*/
|
||||
gus.dmaaddr=(gus.dmaaddr&0xFF000)|(val<<4);
|
||||
break;
|
||||
|
||||
case 0x43: /*Address low*/
|
||||
gus.addr=(gus.addr&0xFFF00)|val;
|
||||
break;
|
||||
case 0x45: /*Timer control*/
|
||||
// printf("Timer control %02X\n",val);
|
||||
gus.tctrl=val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x345: /*Global high*/
|
||||
// if (gus.global!=0x43 && gus.global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X\n",gus.global,gus.voice,val,CS,pc);
|
||||
switch (gus.global)
|
||||
{
|
||||
case 0: /*Voice control*/
|
||||
if (!(val&1) && gus.ctrl[gus.voice]&1)
|
||||
{
|
||||
// printf("Voice on %i - start %05X end %05X freq %04X\n",gus.voice,gus.start[gus.voice],gus.end[gus.voice],gus.freq[gus.voice]);
|
||||
// if (val&0x40) gus.cur[gus.voice]=gus.end[gus.voice]<<8;
|
||||
// else gus.cur[gus.voice]=gus.start[gus.voice]<<8;
|
||||
}
|
||||
if (val&2) val|=1;
|
||||
gus.waveirqs[gus.voice]=val&0x80;
|
||||
gus.ctrl[gus.voice]=val&0x7F;
|
||||
pollgusirqs();
|
||||
break;
|
||||
case 1: /*Frequency control*/
|
||||
gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF)|(val<<8);
|
||||
break;
|
||||
case 2: /*Start addr high*/
|
||||
gus.startx[gus.voice]=(gus.startx[gus.voice]&0x07FFF)|(val<<15);
|
||||
gus.start[gus.voice]=(gus.start[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
|
||||
// printf("Write %i start %08X %08X %02X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice],val);
|
||||
break;
|
||||
case 3: /*Start addr low*/
|
||||
gus.startx[gus.voice]=(gus.startx[gus.voice]&0xFFF80)|(val&0x7F);
|
||||
gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFF00FF)|(val<<8);
|
||||
// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]);
|
||||
break;
|
||||
case 4: /*End addr high*/
|
||||
gus.endx[gus.voice]=(gus.endx[gus.voice]&0x07FFF)|(val<<15);
|
||||
gus.end[gus.voice]=(gus.end[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
|
||||
// printf("Write %i end %08X %08X %02X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice],val);
|
||||
break;
|
||||
case 5: /*End addr low*/
|
||||
gus.endx[gus.voice]=(gus.endx[gus.voice]&0xFFF80)|(val&0x7F);
|
||||
gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFF00FF)|(val<<8);
|
||||
// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]);
|
||||
break;
|
||||
|
||||
case 0x6: /*Ramp frequency*/
|
||||
gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
|
||||
// printf("RFREQ %02X %i %i %f %i\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))),ins);
|
||||
break;
|
||||
case 0x7: /*Ramp start*/
|
||||
gus.rstart[gus.voice]=val<<17;
|
||||
break;
|
||||
case 0x8: /*Ramp end*/
|
||||
gus.rend[gus.voice]=val<<17;
|
||||
break;
|
||||
case 0x9: /*Current volume*/
|
||||
gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE00)|(val<<17);
|
||||
// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]);
|
||||
break;
|
||||
|
||||
case 0xA: /*Current addr high*/
|
||||
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24);
|
||||
gus.curx[gus.voice]=(gus.curx[gus.voice]&0x07FFF00)|((val<<15)<<8);
|
||||
// printf("Write %i cur %08X %08X %02X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice],val);
|
||||
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x007FFF00)|((val<<15)<<8);
|
||||
break;
|
||||
case 0xB: /*Current addr low*/
|
||||
gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFF00FF)|(val<<8);
|
||||
gus.curx[gus.voice]=(gus.curx[gus.voice]&0xFFF8000)|((val&0x7F)<<8);
|
||||
// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0FFF8000)|((val&0x7F)<<8);
|
||||
// printf("Write %i cur %08X %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]);
|
||||
break;
|
||||
case 0xD: /*Ramp control*/
|
||||
if (val&2) val|=1;
|
||||
gus.rampirqs[gus.voice]=val&0x80;
|
||||
gus.rctrl[gus.voice]=val&0x7F;
|
||||
pollgusirqs();
|
||||
// printf("Ramp control %02i %02X %02X %i\n",gus.voice,val,gus.rampirqs[gus.voice],ins);
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
gus.voices=(val&63)+1;
|
||||
if (gus.voices>32) gus.voices=32;
|
||||
if (gus.voices<14) gus.voices=14;
|
||||
gus.global=val;
|
||||
// printf("GUS voices %i\n",val&31);
|
||||
break;
|
||||
|
||||
case 0x41: /*DMA*/
|
||||
if (val&1)
|
||||
{
|
||||
// printf("DMA start! %05X %02X\n",gus.dmaaddr,val);
|
||||
c=0;
|
||||
while (c<65536)
|
||||
{
|
||||
d=readdma3();
|
||||
if (d==-1) break;
|
||||
if (val&0x80) d^=0x80;
|
||||
gusram[gus.dmaaddr]=d;
|
||||
gus.dmaaddr++;
|
||||
gus.dmaaddr&=0xFFFFF;
|
||||
c++;
|
||||
}
|
||||
// printf("Transferred %i bytes\n",c);
|
||||
gus.dmactrl=val&~0x40;
|
||||
if (val&0x20) gusirqnext=1;
|
||||
// exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x42: /*DMA address low*/
|
||||
gus.dmaaddr=(gus.dmaaddr&0xFF0)|(val<<12);
|
||||
break;
|
||||
|
||||
case 0x43: /*Address low*/
|
||||
gus.addr=(gus.addr&0xF00FF)|(val<<8);
|
||||
break;
|
||||
case 0x44: /*Address high*/
|
||||
gus.addr=(gus.addr&0xFFFF)|((val<<16)&0xF0000);
|
||||
break;
|
||||
case 0x45: /*Timer control*/
|
||||
if (!(val&4)) gus.irqstatus&=~4;
|
||||
if (!(val&8)) gus.irqstatus&=~8;
|
||||
// printf("Timer control %02X\n",val);
|
||||
/* if ((val&4) && !(gus.tctrl&4))
|
||||
{
|
||||
gus.t1=gus.t1l;
|
||||
gus.t1on=1;
|
||||
}*/
|
||||
gus.tctrl=val;
|
||||
break;
|
||||
case 0x46: /*Timer 1*/
|
||||
gus.t1=gus.t1l=val;
|
||||
gus.t1on=1;
|
||||
// printf("GUS timer 1 %i\n",val);
|
||||
break;
|
||||
case 0x47: /*Timer 2*/
|
||||
gus.t2=gus.t2l=val<<2;
|
||||
gus.t2on=1;
|
||||
// printf("GUS timer 2 %i\n",val);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x347: /*DRAM access*/
|
||||
gusram[gus.addr]=val;
|
||||
// pclog("GUS RAM write %05X %02X\n",gus.addr,val);
|
||||
gus.addr&=0xFFFFF;
|
||||
break;
|
||||
case 0x248: case 0x388: gus.adcommand=val; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readgus(uint16_t addr)
|
||||
{
|
||||
uint8_t val;
|
||||
// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus.global);
|
||||
// output=3;
|
||||
switch (addr)
|
||||
{
|
||||
case 0x240: return 0;
|
||||
case 0x246: /*IRQ status*/
|
||||
val=gus.irqstatus;
|
||||
// printf("246 status %02X\n",val);
|
||||
// gus.irqstatus=0;
|
||||
// if (gus.irqstatus2==0xE0) picintc(0x20);
|
||||
return val;
|
||||
case 0x24A:
|
||||
return gus.adcommand;
|
||||
case 0x24B: case 0x24F: return 0;
|
||||
case 0x340: /*MIDI status*/
|
||||
case 0x341: /*MIDI data*/
|
||||
return 0;
|
||||
case 0x342: return gus.voice;
|
||||
case 0x343: return gus.global;
|
||||
case 0x344: /*Global low*/
|
||||
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("Reading register %02X %02X\n",gus.global,gus.voice);
|
||||
switch (gus.global)
|
||||
{
|
||||
case 0x82: /*Start addr high*/
|
||||
return gus.start[gus.voice]>>16;
|
||||
case 0x83: /*Start addr low*/
|
||||
return gus.start[gus.voice]&0xFF;
|
||||
|
||||
case 0x89: /*Current volume*/
|
||||
return gus.rcur[gus.voice]>>9;
|
||||
case 0x8A: /*Current addr high*/
|
||||
return gus.cur[gus.voice]>>16;
|
||||
case 0x8B: /*Current addr low*/
|
||||
return gus.cur[gus.voice]&0xFF;
|
||||
|
||||
case 0x8F: /*IRQ status*/
|
||||
val=gus.irqstatus2;
|
||||
// pclog("Read IRQ status - %02X\n",val);
|
||||
gus.rampirqs[gus.irqstatus2&0x1F]=0;
|
||||
gus.waveirqs[gus.irqstatus2&0x1F]=0;
|
||||
pollgusirqs();
|
||||
return val;
|
||||
}
|
||||
//fatal("Bad GUS global low read %02X\n",gus.global);
|
||||
break;
|
||||
case 0x345: /*Global high*/
|
||||
// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("HReading register %02X %02X\n",gus.global,gus.voice);
|
||||
switch (gus.global)
|
||||
{
|
||||
case 0x80: /*Voice control*/
|
||||
return gus.ctrl[gus.voice]|(gus.waveirqs[gus.voice]?0x80:0);
|
||||
|
||||
case 0x82: /*Start addr high*/
|
||||
return gus.start[gus.voice]>>24;
|
||||
case 0x83: /*Start addr low*/
|
||||
return gus.start[gus.voice]>>8;
|
||||
|
||||
case 0x89: /*Current volume*/
|
||||
return gus.rcur[gus.voice]>>17;
|
||||
|
||||
case 0x8A: /*Current addr high*/
|
||||
return gus.cur[gus.voice]>>24;
|
||||
case 0x8B: /*Current addr low*/
|
||||
return gus.cur[gus.voice]>>8;
|
||||
|
||||
case 0x8D:
|
||||
// pclog("Read ramp control %02X %08X %08X %08X %08X\n",gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0),gus.rcur[gus.voice],gus.rfreq[gus.voice],gus.rstart[gus.voice],gus.rend[gus.voice]);
|
||||
return gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0);
|
||||
|
||||
case 0x8F: /*IRQ status*/
|
||||
val=gus.irqstatus2;
|
||||
// pclog("Read IRQ status - %02X\n",val);
|
||||
gus.rampirqs[gus.irqstatus2&0x1F]=0;
|
||||
gus.waveirqs[gus.irqstatus2&0x1F]=0;
|
||||
pollgusirqs();
|
||||
return val;
|
||||
|
||||
case 0x41: /*DMA control*/
|
||||
val=gus.dmactrl|((gus.irqstatus&0x80)?0x40:0);
|
||||
gus.irqstatus&=~0x80;
|
||||
return val;
|
||||
case 0x45: /*Timer control*/
|
||||
return gus.tctrl;
|
||||
case 0x49: /*Sampling control*/
|
||||
return 0;
|
||||
}
|
||||
//fatal("Bad GUS global high read %02X\n",gus.global);
|
||||
break;
|
||||
case 0x346: return 0;
|
||||
case 0x347: /*DRAM access*/
|
||||
val=gusram[gus.addr];
|
||||
// pclog("GUS RAM read %05X %02X\n",gus.addr,val);
|
||||
// output=3;
|
||||
gus.addr&=0xFFFFF;
|
||||
return val;
|
||||
case 0x349: return 0;
|
||||
}
|
||||
// printf("Bad GUS read %04X! %02X\n",addr,gus.global);
|
||||
// exit(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pollgus()
|
||||
{
|
||||
if (gus.t1on)
|
||||
{
|
||||
gus.t1++;
|
||||
if (gus.t1>=0xFF)
|
||||
{
|
||||
// gus.t1on=0;
|
||||
gus.t1=gus.t1l;
|
||||
if (gus.tctrl&4)
|
||||
{
|
||||
picintlevel(0x20);
|
||||
gus.irqstatus|=4;
|
||||
// printf("GUS T1 IRQ!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gusirqnext)
|
||||
{
|
||||
gusirqnext=0;
|
||||
gus.irqstatus|=0x80;
|
||||
picintlevel(0x20);
|
||||
}
|
||||
}
|
||||
|
||||
void pollgus2()
|
||||
{
|
||||
if (gus.t2on)
|
||||
{
|
||||
gus.t2++;
|
||||
if (gus.t2>=(0xFF<<2))
|
||||
{
|
||||
// gus.t2on=0;
|
||||
gus.t2=gus.t2l;
|
||||
if (gus.tctrl&8)
|
||||
{
|
||||
picintlevel(0x20);
|
||||
gus.irqstatus|=8;
|
||||
// printf("GUS T2 IRQ!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gusirqnext)
|
||||
{
|
||||
gusirqnext=0;
|
||||
gus.irqstatus|=0x80;
|
||||
picintlevel(0x20);
|
||||
}
|
||||
}
|
||||
|
||||
float gusfreqs[]=
|
||||
{
|
||||
44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696,
|
||||
23746,22866,22050,21289,20580,19916,19293
|
||||
};
|
||||
|
||||
int16_t gusbufferx[65536];
|
||||
int guspos=0;
|
||||
void getgus(int16_t *p, int count)
|
||||
{
|
||||
memcpy(p,gusbufferx,count*4);
|
||||
// printf("Get %i samples %i\n",guspos,count);
|
||||
guspos=0;
|
||||
pollgusirqs();
|
||||
}
|
||||
|
||||
void pollgussamp()
|
||||
{
|
||||
uint32_t addr;
|
||||
int c,d;
|
||||
int16_t v;
|
||||
int32_t vl;
|
||||
int16_t p[2];
|
||||
float GUSRATECONST;
|
||||
if (guspos>65500) return;
|
||||
// return;
|
||||
if (gus.voices<14) GUSRATECONST=44100.0/48000.0;
|
||||
else GUSRATECONST=gusfreqs[gus.voices-14]/48000.0;
|
||||
// printf("Voices %i freq %f\n",gus.voices,GUSRATECONST*48000.0);
|
||||
// for (c=0;c<count;c++)
|
||||
// {
|
||||
p[0]=p[1]=0;
|
||||
for (d=0;d<32;d++)
|
||||
{
|
||||
if (!(gus.ctrl[d]&1))
|
||||
{
|
||||
if (gus.ctrl[d]&4)
|
||||
{
|
||||
addr=gus.cur[d]>>9;
|
||||
addr=(addr&0xC0000)|((addr<<1)&0x3FFFE);
|
||||
if (!(gus.freq[d]>>10)) /*Interpolate*/
|
||||
{
|
||||
vl=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80)*(511-(gus.cur[d]&511));
|
||||
vl+=(int16_t)(int8_t)((gusram[(addr+3)&0xFFFFF]^0x80)-0x80)*(gus.cur[d]&511);
|
||||
v=vl>>9;
|
||||
}
|
||||
else
|
||||
v=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(gus.freq[d]>>10)) /*Interpolate*/
|
||||
{
|
||||
vl=((int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80))*(511-(gus.cur[d]&511));
|
||||
vl+=((int8_t)((gusram[((gus.cur[d]>>9)+1)&0xFFFFF]^0x80)-0x80))*(gus.cur[d]&511);
|
||||
v=vl>>9;
|
||||
}
|
||||
else
|
||||
v=(int16_t)(int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80);
|
||||
}
|
||||
// v=(int16_t)((float)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80)*32.0*vol16bit[(gus.rcur[d]>>13)&4095]);
|
||||
if ((gus.rcur[d]>>13)>4095) v=(int16_t)(float)(v)*24.0*vol16bit[4095];
|
||||
else v=(int16_t)(float)(v)*24.0*vol16bit[(gus.rcur[d]>>13)&4095];
|
||||
// if (!d) printf("%08X %08X %08X %05X %08X %08X %04X %f %04X %08X %i\n",gus.cur[d],gus.start[d],gus.end[d],gus.cur[d]>>9,gus.startx[d],gus.endx[d],gus.rcur[d],vol16bit[0],v,gus.freq[d],ins);
|
||||
// if (!d)
|
||||
// {
|
||||
p[0]+=v;
|
||||
p[1]+=v;
|
||||
// }
|
||||
// printf("Data from %08X\n",gus.cur[d]>>8);
|
||||
if (gus.ctrl[d]&0x40)
|
||||
{
|
||||
gus.cur[d]-=(gus.freq[d]>>1)*GUSRATECONST;
|
||||
if (gus.cur[d]<=gus.start[d])
|
||||
{
|
||||
if (!(gus.rctrl[d]&4))
|
||||
{
|
||||
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
|
||||
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
|
||||
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
|
||||
}
|
||||
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gus.cur[d]+=(gus.freq[d]>>1)*GUSRATECONST;
|
||||
// pclog("GUS add %08X %f\n",gus.freq[d],GUSRATECONST);
|
||||
if (gus.cur[d]>=gus.end[d])
|
||||
{
|
||||
if (!(gus.rctrl[d]&4))
|
||||
{
|
||||
// gus.ctrl[d]|=1;
|
||||
if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1;
|
||||
else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40;
|
||||
gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d];
|
||||
}
|
||||
if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(gus.rctrl[d]&1))
|
||||
{
|
||||
if (gus.rctrl[d]&0x40)
|
||||
{
|
||||
gus.rcur[d]-=gus.rfreq[d]*GUSRATECONST*16;
|
||||
// printf("RCUR- %i %i %i %i %i\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
|
||||
if (gus.rcur[d]<=gus.rstart[d])
|
||||
{
|
||||
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rend[d]<<8;
|
||||
else gus.rctrl[d]|=1;
|
||||
if (gus.rctrl[d]&0x20)
|
||||
{
|
||||
gus.rampirqs[d]=1;
|
||||
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gus.rcur[d]+=gus.rfreq[d]*GUSRATECONST*16;
|
||||
// printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]);
|
||||
if (gus.rcur[d]>=gus.rend[d])
|
||||
{
|
||||
if (gus.rctrl[d]&8) gus.rcur[d]=gus.rstart[d]<<8;
|
||||
else gus.rctrl[d]|=1;
|
||||
if (gus.rctrl[d]&0x20)
|
||||
{
|
||||
gus.rampirqs[d]=1;
|
||||
// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gusbufferx[guspos++]=p[0];
|
||||
gusbufferx[guspos++]=p[1];
|
||||
if (guspos==65536) guspos=0;
|
||||
// }
|
||||
pollgusirqs();
|
||||
}
|
||||
|
||||
void gus_init()
|
||||
{
|
||||
io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
|
||||
io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL);
|
||||
io_sethandler(0x0388, 0x0001, NULL, NULL, NULL, writegus, NULL, NULL);
|
||||
}
|
||||
96
src/i430vx.c
Normal file
96
src/i430vx.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "i430vx.h"
|
||||
|
||||
static uint8_t card_i430vx[256];
|
||||
|
||||
static void i430vx_map(uint32_t addr, uint32_t size, int state)
|
||||
{
|
||||
switch (state & 3)
|
||||
{
|
||||
case 0x0: mem_sethandler(addr, size, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL , NULL); break; /*DRAM disabled, accesses directed to PCI bus*/
|
||||
case 0x1: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL , NULL); break; /*Read only, DRAM write protected, non-cacheable*/
|
||||
case 0x2: mem_sethandler(addr, size, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml, NULL); break; /*Write only*/
|
||||
case 0x3: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, NULL); break; /*Read/write, non-cacheable*/
|
||||
/*Below are redundant*/
|
||||
// case 0x5: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break; /*Read only, DRAM write protected, cacheable*/
|
||||
// case 0x7: mem_sethandler(addr, size, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break; /*Read/write, non-cacheable*/
|
||||
}
|
||||
flushmmucache_nopc();
|
||||
}
|
||||
void i430vx_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
if (func)
|
||||
return;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0e:
|
||||
return;
|
||||
|
||||
case 0x59: /*PAM0*/
|
||||
if ((card_i430vx[0x59] ^ val) & 0xf0)
|
||||
{
|
||||
i430vx_map(0xf0000, 0x10000, val >> 4);
|
||||
shadowbios = (val & 0x10);
|
||||
}
|
||||
pclog("i430vx_write : PAM0 write %02X\n", val);
|
||||
break;
|
||||
case 0x5e: /*PAM5*/
|
||||
if ((card_i430vx[0x5e] ^ val) & 0x0f)
|
||||
i430vx_map(0xe0000, 0x04000, val & 0xf);
|
||||
if ((card_i430vx[0x5e] ^ val) & 0xf0)
|
||||
i430vx_map(0xe4000, 0x04000, val >> 4);
|
||||
pclog("i430vx_write : PAM5 write %02X\n", val);
|
||||
break;
|
||||
case 0x5f: /*PAM6*/
|
||||
if ((card_i430vx[0x5f] ^ val) & 0x0f)
|
||||
i430vx_map(0xe8000, 0x04000, val & 0xf);
|
||||
if ((card_i430vx[0x5f] ^ val) & 0xf0)
|
||||
i430vx_map(0xec000, 0x04000, val >> 4);
|
||||
pclog("i430vx_write : PAM6 write %02X\n", val);
|
||||
break;
|
||||
}
|
||||
|
||||
card_i430vx[addr] = val;
|
||||
}
|
||||
|
||||
uint8_t i430vx_read(int func, int addr, void *priv)
|
||||
{
|
||||
if (func)
|
||||
return 0xff;
|
||||
|
||||
return card_i430vx[addr];
|
||||
}
|
||||
|
||||
|
||||
void i430vx_init()
|
||||
{
|
||||
pci_add_specific(0, i430vx_read, i430vx_write, NULL);
|
||||
|
||||
memset(card_i430vx, 0, 256);
|
||||
card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/
|
||||
card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/
|
||||
card_i430vx[0x04] = 0x06; card_i430vx[0x05] = 0x00;
|
||||
card_i430vx[0x06] = 0x00; card_i430vx[0x07] = 0x02;
|
||||
card_i430vx[0x08] = 0x00; /*A0 stepping*/
|
||||
card_i430vx[0x09] = 0x00; card_i430vx[0x0a] = 0x00; card_i430vx[0x0b] = 0x06;
|
||||
card_i430vx[0x52] = 0x42; /*256kb PLB cache*/
|
||||
card_i430vx[0x53] = 0x14;
|
||||
card_i430vx[0x56] = 0x52; /*DRAM control*/
|
||||
card_i430vx[0x57] = 0x01;
|
||||
card_i430vx[0x60] = card_i430vx[0x61] = card_i430vx[0x62] = card_i430vx[0x63] = card_i430vx[0x64] = 0x02;
|
||||
card_i430vx[0x67] = 0x11;
|
||||
card_i430vx[0x69] = 0x03;
|
||||
card_i430vx[0x70] = 0x20;
|
||||
card_i430vx[0x72] = 0x02;
|
||||
card_i430vx[0x74] = 0x0e;
|
||||
card_i430vx[0x78] = 0x23;
|
||||
}
|
||||
1
src/i430vx.h
Normal file
1
src/i430vx.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void i430vx_init();
|
||||
303
src/piix.c
Normal file
303
src/piix.c
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*PRD format :
|
||||
|
||||
word 0 - base address
|
||||
word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "ibm.h"
|
||||
#include "ide.h"
|
||||
#include "io.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "piix.h"
|
||||
|
||||
uint8_t piix_bus_master_read(uint16_t port, void *priv);
|
||||
void piix_bus_master_write(uint16_t port, uint8_t val, void *priv);
|
||||
|
||||
static uint8_t card_piix[256], card_piix_ide[256];
|
||||
|
||||
void piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
if (func > 1)
|
||||
return;
|
||||
|
||||
if (func == 1) /*IDE*/
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0e:
|
||||
return;
|
||||
case 0x20:
|
||||
val |= 1;
|
||||
break;
|
||||
case 0x41:
|
||||
if ((val ^ card_piix_ide[0x41]) & 0x80)
|
||||
{
|
||||
if (val & 0x80)
|
||||
ide_pri_enable();
|
||||
else
|
||||
ide_pri_disable();
|
||||
}
|
||||
break;
|
||||
case 0x43:
|
||||
if ((val ^ card_piix_ide[0x43]) & 0x80)
|
||||
{
|
||||
if (val & 0x80)
|
||||
ide_sec_enable();
|
||||
else
|
||||
ide_sec_disable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
card_piix_ide[addr] = val;
|
||||
if ((addr & ~3) == 0x20) /*Bus master base address*/
|
||||
{
|
||||
uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8);
|
||||
io_removehandler(0, 0x10000, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL);
|
||||
io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL);
|
||||
}
|
||||
// pclog("PIIX write %02X %02X\n", addr, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0e:
|
||||
return;
|
||||
}
|
||||
card_piix[addr] = val;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t piix_read(int func, int addr, void *priv)
|
||||
{
|
||||
if (func > 1)
|
||||
return 0xff;
|
||||
|
||||
if (func == 1) /*IDE*/
|
||||
{
|
||||
// pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]);
|
||||
return card_piix_ide[addr];
|
||||
}
|
||||
else
|
||||
return card_piix[addr];
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t command;
|
||||
uint8_t status;
|
||||
uint32_t ptr, ptr_cur;
|
||||
int count;
|
||||
uint32_t addr;
|
||||
int eot;
|
||||
} piix_busmaster[2];
|
||||
|
||||
static void piix_bus_master_next_addr(int channel)
|
||||
{
|
||||
piix_busmaster[channel].addr = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur])) & ~1;
|
||||
piix_busmaster[channel].count = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur + 4])) & 0xfffe;
|
||||
piix_busmaster[channel].eot = (*(unsigned long *)(&ram[piix_busmaster[channel].ptr_cur + 4])) >> 31;
|
||||
piix_busmaster[channel].ptr_cur += 8;
|
||||
// pclog("New DMA settings on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot);
|
||||
}
|
||||
|
||||
void piix_bus_master_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
int channel = (port & 8) ? 1 : 0;
|
||||
// pclog("PIIX Bus Master write %04X %02X\n", port, val);
|
||||
switch (port & 7)
|
||||
{
|
||||
case 0:
|
||||
if ((val & 1) && !(piix_busmaster[channel].command & 1)) /*Start*/
|
||||
{
|
||||
piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr;
|
||||
piix_bus_master_next_addr(channel);
|
||||
piix_busmaster[channel].status |= 1;
|
||||
}
|
||||
if (!(val & 1) && (piix_busmaster[channel].command & 1)) /*Stop*/
|
||||
piix_busmaster[channel].status &= ~1;
|
||||
|
||||
piix_busmaster[channel].command = val;
|
||||
break;
|
||||
case 2:
|
||||
piix_busmaster[channel].status = (val & 0x60) | ((piix_busmaster[channel].status & ~val) & 6) | (piix_busmaster[channel].status & 1);
|
||||
break;
|
||||
case 4:
|
||||
piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffffff00) | val;
|
||||
break;
|
||||
case 5:
|
||||
piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00ff) | (val << 8);
|
||||
break;
|
||||
case 6:
|
||||
piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00ffff) | (val << 16);
|
||||
break;
|
||||
case 7:
|
||||
piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00ffffff) | (val << 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t piix_bus_master_read(uint16_t port, void *priv)
|
||||
{
|
||||
int channel = (port & 8) ? 1 : 0;
|
||||
switch (port & 7)
|
||||
{
|
||||
case 0:
|
||||
return piix_busmaster[channel].command;
|
||||
case 2:
|
||||
return piix_busmaster[channel].status;
|
||||
case 4:
|
||||
return piix_busmaster[channel].ptr;
|
||||
case 5:
|
||||
return piix_busmaster[channel].ptr >> 8;
|
||||
case 6:
|
||||
return piix_busmaster[channel].ptr >> 16;
|
||||
case 7:
|
||||
return piix_busmaster[channel].ptr >> 24;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
int piix_bus_master_sector_read(int channel, uint8_t *data)
|
||||
{
|
||||
int transferred = 0;
|
||||
|
||||
if (!(piix_busmaster[channel].status & 1))
|
||||
return 1; /*DMA disabled*/
|
||||
|
||||
while (transferred < 512)
|
||||
{
|
||||
if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot)
|
||||
fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot);
|
||||
|
||||
if (piix_busmaster[channel].count < (512 - transferred))
|
||||
{
|
||||
// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count);
|
||||
memcpy(&ram[piix_busmaster[channel].addr], data + transferred, piix_busmaster[channel].count);
|
||||
transferred += piix_busmaster[channel].count;
|
||||
piix_busmaster[channel].addr += piix_busmaster[channel].count;
|
||||
piix_busmaster[channel].count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("Transferring larger - %i bytes\n", 512 - transferred);
|
||||
memcpy(&ram[piix_busmaster[channel].addr], data + transferred, 512 - transferred);
|
||||
piix_busmaster[channel].addr += (512 - transferred);
|
||||
piix_busmaster[channel].count -= (512 - transferred);
|
||||
transferred += (512 - transferred);
|
||||
}
|
||||
|
||||
// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot);
|
||||
|
||||
if (!piix_busmaster[channel].count)
|
||||
{
|
||||
// pclog("DMA on channel %i - block over\n", channel);
|
||||
if (piix_busmaster[channel].eot) /*End of transfer?*/
|
||||
{
|
||||
// pclog("DMA on channel %i - transfer over\n", channel);
|
||||
piix_busmaster[channel].status &= ~1;
|
||||
}
|
||||
else
|
||||
piix_bus_master_next_addr(channel);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int piix_bus_master_sector_write(int channel, uint8_t *data)
|
||||
{
|
||||
int transferred = 0;
|
||||
|
||||
if (!(piix_busmaster[channel].status & 1))
|
||||
return 1; /*DMA disabled*/
|
||||
|
||||
while (transferred < 512)
|
||||
{
|
||||
if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot)
|
||||
fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot);
|
||||
|
||||
if (piix_busmaster[channel].count < (512 - transferred))
|
||||
{
|
||||
// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count);
|
||||
memcpy(data + transferred, &ram[piix_busmaster[channel].addr], piix_busmaster[channel].count);
|
||||
transferred += piix_busmaster[channel].count;
|
||||
piix_busmaster[channel].addr += piix_busmaster[channel].count;
|
||||
piix_busmaster[channel].count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("Transferring larger - %i bytes\n", 512 - transferred);
|
||||
memcpy(data + transferred, &ram[piix_busmaster[channel].addr], 512 - transferred);
|
||||
piix_busmaster[channel].addr += (512 - transferred);
|
||||
piix_busmaster[channel].count -= (512 - transferred);
|
||||
transferred += (512 - transferred);
|
||||
}
|
||||
|
||||
// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot);
|
||||
|
||||
if (!piix_busmaster[channel].count)
|
||||
{
|
||||
// pclog("DMA on channel %i - block over\n", channel);
|
||||
if (piix_busmaster[channel].eot) /*End of transfer?*/
|
||||
{
|
||||
// pclog("DMA on channel %i - transfer over\n", channel);
|
||||
piix_busmaster[channel].status &= ~1;
|
||||
}
|
||||
else
|
||||
piix_bus_master_next_addr(channel);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void piix_bus_master_set_irq(int channel)
|
||||
{
|
||||
piix_busmaster[channel].status |= 4;
|
||||
}
|
||||
|
||||
void piix_init(int card)
|
||||
{
|
||||
pci_add_specific(card, piix_read, piix_write, NULL);
|
||||
|
||||
memset(card_piix, 0, 256);
|
||||
card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/
|
||||
card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/
|
||||
card_piix[0x04] = 0x07; card_piix[0x05] = 0x00;
|
||||
card_piix[0x06] = 0x00; card_piix[0x07] = 0x02;
|
||||
card_piix[0x08] = 0x00; /*A0 stepping*/
|
||||
card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06;
|
||||
card_piix[0x0e] = 0x80; /*Multi-function device*/
|
||||
card_piix[0x4c] = 0x4d;
|
||||
card_piix[0x4e] = 0x03;
|
||||
card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80;
|
||||
card_piix[0x69] = 0x02;
|
||||
card_piix[0x70] = card_piix[0x71] = 0x80;
|
||||
card_piix[0x76] = card_piix[0x77] = 0x0c;
|
||||
card_piix[0x78] = 0x02; card_piix[0x79] = 0x00;
|
||||
card_piix[0xa0] = 0x08;
|
||||
card_piix[0xa2] = card_piix[0xa3] = 0x00;
|
||||
card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00;
|
||||
card_piix[0xa8] = 0x0f;
|
||||
card_piix[0xaa] = card_piix[0xab] = 0x00;
|
||||
card_piix[0xac] = 0x00;
|
||||
card_piix[0xae] = 0x00;
|
||||
|
||||
card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/
|
||||
card_piix_ide[0x02] = 0x30; card_piix_ide[0x03] = 0x12; /*82371FB (PIIX)*/
|
||||
card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00;
|
||||
card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02;
|
||||
card_piix_ide[0x08] = 0x00;
|
||||
card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01;
|
||||
card_piix_ide[0x0d] = 0x00;
|
||||
card_piix_ide[0x0e] = 0x00;
|
||||
card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/
|
||||
card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00;
|
||||
card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00;
|
||||
|
||||
ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq);
|
||||
}
|
||||
1
src/piix.h
Normal file
1
src/piix.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void piix_init(int card);
|
||||
|
|
@ -1 +0,0 @@
|
|||
extern int wasgated;
|
||||
206
src/psg.c
206
src/psg.c
|
|
@ -1,206 +0,0 @@
|
|||
#include "ibm.h"
|
||||
|
||||
float volslog[16]=
|
||||
{
|
||||
0.00000f,0.59715f,0.75180f,0.94650f,
|
||||
1.19145f,1.50000f,1.88835f,2.37735f,
|
||||
2.99295f,3.76785f,4.74345f,5.97165f,
|
||||
7.51785f,9.46440f,11.9194f,15.0000f
|
||||
};
|
||||
|
||||
float psgcount[4],psglatch[4];
|
||||
int psgstat[4];
|
||||
int snlatch[4],sncount[4];
|
||||
int snfreqlo[4],snfreqhi[4];
|
||||
int snvol[4];
|
||||
int curfreq[4];
|
||||
uint32_t snshift[2]={0x8000,0x8000};
|
||||
|
||||
#define SNCLOCK (2386360>>5)
|
||||
uint8_t snnoise;
|
||||
|
||||
void initpsg()
|
||||
{
|
||||
int c;
|
||||
for (c=0;c<4;c++)
|
||||
{
|
||||
psgcount[c]=psglatch[c]=100000;
|
||||
psgstat[c]=0;
|
||||
}
|
||||
}
|
||||
|
||||
#define PSGCONST (32000.0/48000.0)
|
||||
|
||||
void getpsg(signed short *p, int size)
|
||||
{
|
||||
// printf("Getpsg %08X %i\n",p,size);
|
||||
// return;
|
||||
int c,d;
|
||||
for (c=0;c<size;c++)
|
||||
{
|
||||
p[c]=0;
|
||||
for (d=1;d<4;d++)
|
||||
{
|
||||
if (psgstat[d]) p[c]+=volslog[snvol[d]]*170;
|
||||
else p[c]-=volslog[snvol[d]]*170;
|
||||
psgcount[d]-=(512*PSGCONST);
|
||||
while (psgcount[d]<=0.0 && psglatch[d]>1.0)
|
||||
{
|
||||
psgcount[d]+=psglatch[d];
|
||||
psgstat[d]^=1;
|
||||
}
|
||||
if (psgcount[d]<=0.0) psgcount[d]=1.0;
|
||||
}
|
||||
d=(snnoise&4)?0:1;
|
||||
if (snshift[d]&1) p[c]+=volslog[snvol[0]]*170;
|
||||
psgcount[0]-=(512*PSGCONST);
|
||||
while (psgcount[0]<=0.0 && psglatch[0]>1.0)
|
||||
{
|
||||
psgcount[0]+=psglatch[0];
|
||||
snshift[1]>>=1;
|
||||
if (!snshift[1]) snshift[1]=0x4000;
|
||||
if ((snshift[0]&1)^((snshift[0]&4)?1:0)^((snshift[0]&0x8000)?1:0))
|
||||
snshift[0]|=0x10000;
|
||||
snshift[0]>>=1;
|
||||
}
|
||||
if (psgcount[0]<=0.0) psgcount[0]=1.0;
|
||||
}
|
||||
}
|
||||
|
||||
int lasttone;
|
||||
uint8_t firstdat;
|
||||
void writepsg(uint16_t addr, uint8_t data)
|
||||
{
|
||||
int c;
|
||||
int freq;
|
||||
pclog("Write PSG %02X\n", data);
|
||||
if (data&0x80)
|
||||
{
|
||||
firstdat=data;
|
||||
switch (data&0x70)
|
||||
{
|
||||
case 0:
|
||||
snfreqlo[3]=data&0xF;
|
||||
lasttone=3;
|
||||
break;
|
||||
case 0x10:
|
||||
data&=0xF;
|
||||
snvol[3]=0xF-data;
|
||||
break;
|
||||
case 0x20:
|
||||
snfreqlo[2]=data&0xF;
|
||||
lasttone=2;
|
||||
break;
|
||||
case 0x30:
|
||||
data&=0xF;
|
||||
snvol[2]=0xF-data;
|
||||
break;
|
||||
case 0x40:
|
||||
snfreqlo[1]=data&0xF;
|
||||
lasttone=1;
|
||||
break;
|
||||
case 0x50:
|
||||
data&=0xF;
|
||||
snvol[1]=0xF-data;
|
||||
break;
|
||||
case 0x60:
|
||||
if ((data&3)!=(snnoise&3)) sncount[0]=0;
|
||||
snnoise=data&0xF;
|
||||
if ((data&3)==3)
|
||||
{
|
||||
curfreq[0]=curfreq[1]>>4;
|
||||
snlatch[0]=snlatch[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (data&3)
|
||||
{
|
||||
case 0:
|
||||
snlatch[0]=128<<7;
|
||||
curfreq[0]=SNCLOCK/256;
|
||||
snlatch[0]=0x400;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 1:
|
||||
snlatch[0]=256<<7;
|
||||
curfreq[0]=SNCLOCK/512;
|
||||
snlatch[0]=0x800;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 2:
|
||||
snlatch[0]=512<<7;
|
||||
curfreq[0]=SNCLOCK/1024;
|
||||
snlatch[0]=0x1000;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 3:
|
||||
snlatch[0]=snlatch[1];
|
||||
sncount[0]=0;
|
||||
}
|
||||
if (snnoise&4) snlatch[0]<<=1;
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
data&=0xF;
|
||||
snvol[0]=0xF-data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((firstdat&0x70)==0x60)
|
||||
{
|
||||
if ((data&3)!=(snnoise&3)) sncount[0]=0;
|
||||
snnoise=data&0xF;
|
||||
if ((data&3)==3)
|
||||
{
|
||||
curfreq[0]=curfreq[1]>>4;
|
||||
snlatch[0]=snlatch[1];
|
||||
// printf("SN 0 latch %04X\n",snlatch[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (data&3)
|
||||
{
|
||||
case 0:
|
||||
snlatch[0]=128<<7;
|
||||
curfreq[0]=SNCLOCK/256;
|
||||
snlatch[0]=0x400;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 1:
|
||||
snlatch[0]=256<<7;
|
||||
curfreq[0]=SNCLOCK/512;
|
||||
snlatch[0]=0x800;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 2:
|
||||
snlatch[0]=512<<7;
|
||||
curfreq[0]=SNCLOCK/1024;
|
||||
snlatch[0]=0x1000;
|
||||
sncount[0]=0;
|
||||
break;
|
||||
case 3:
|
||||
snlatch[0]=snlatch[1];
|
||||
// printf("SN 0 latch %04X\n",snlatch[0]);
|
||||
sncount[0]=0;
|
||||
}
|
||||
if (snnoise&4) snlatch[0]<<=1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
snfreqhi[lasttone]=data&0x3F;
|
||||
freq=snfreqlo[lasttone]|(snfreqhi[lasttone]<<4);
|
||||
snlatch[lasttone]=freq<<6;
|
||||
}
|
||||
}
|
||||
for (c=0;c<4;c++) psglatch[c]=(float)snlatch[c];
|
||||
}
|
||||
|
||||
void psg_init()
|
||||
{
|
||||
pclog("psg_init\n");
|
||||
io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, writepsg, NULL, NULL);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
void psg_init();
|
||||
1104
src/sblaster.c
1104
src/sblaster.c
File diff suppressed because it is too large
Load diff
62
src/sound_adlib.c
Normal file
62
src/sound_adlib.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include "sound_adlib.h"
|
||||
#include "sound_opl.h"
|
||||
|
||||
typedef struct adlib_t
|
||||
{
|
||||
opl_t opl;
|
||||
int16_t buffer[SOUNDBUFLEN * 2];
|
||||
int pos;
|
||||
} adlib_t;
|
||||
|
||||
static void adlib_poll(void *p)
|
||||
{
|
||||
adlib_t *adlib = (adlib_t *)p;
|
||||
|
||||
if (adlib->pos >= SOUNDBUFLEN) return;
|
||||
|
||||
opl2_poll(&adlib->opl, &adlib->buffer[adlib->pos * 2], &adlib->buffer[(adlib->pos * 2) + 1]);
|
||||
adlib->pos++;
|
||||
}
|
||||
|
||||
static void adlib_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
adlib_t *adlib = (adlib_t *)p;
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
buffer[c] += adlib->buffer[c];
|
||||
|
||||
adlib->pos = 0;
|
||||
}
|
||||
|
||||
void *adlib_init()
|
||||
{
|
||||
adlib_t *adlib = malloc(sizeof(adlib_t));
|
||||
memset(adlib, 0, sizeof(adlib_t));
|
||||
|
||||
pclog("adlib_init\n");
|
||||
opl2_init(&adlib->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl);
|
||||
sound_add_handler(adlib_poll, adlib_get_buffer, adlib);
|
||||
return adlib;
|
||||
}
|
||||
|
||||
void adlib_close(void *p)
|
||||
{
|
||||
adlib_t *adlib = (adlib_t *)p;
|
||||
|
||||
free(adlib);
|
||||
}
|
||||
|
||||
device_t adlib_device =
|
||||
{
|
||||
"AdLib",
|
||||
adlib_init,
|
||||
adlib_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_adlib.h
Normal file
1
src/sound_adlib.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t adlib_device;
|
||||
597
src/sound_adlibgold.c
Normal file
597
src/sound_adlibgold.c
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
|
||||
#include "sound_opl.h"
|
||||
#include "dma.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "timer.h"
|
||||
|
||||
void adgold_timer_poll();
|
||||
|
||||
typedef struct adgold_t
|
||||
{
|
||||
int adgold_irq_status;
|
||||
|
||||
uint8_t adgold_eeprom[0x19];
|
||||
|
||||
uint8_t adgold_status;
|
||||
int adgold_38x_state, adgold_38x_addr;
|
||||
uint8_t adgold_38x_regs[0x19];
|
||||
|
||||
int adgold_mma_addr;
|
||||
uint8_t adgold_mma_regs[2][0xe];
|
||||
|
||||
int adgold_mma_enable[2];
|
||||
uint8_t adgold_mma_fifo[2][256];
|
||||
int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2];
|
||||
uint8_t adgold_mma_status;
|
||||
|
||||
int16_t adgold_mma_out[2];
|
||||
int adgold_mma_intpos[2];
|
||||
|
||||
int adgold_mma_timer_count;
|
||||
|
||||
struct
|
||||
{
|
||||
int timer0_latch, timer0_count;
|
||||
int timerbase_latch, timerbase_count;
|
||||
int timer1_latch, timer1_count;
|
||||
int timer2_latch, timer2_count, timer2_read;
|
||||
|
||||
int voice_count[2], voice_latch[2];
|
||||
} adgold_mma;
|
||||
|
||||
opl_t opl;
|
||||
|
||||
int16_t opl_buffer[SOUNDBUFLEN * 2];
|
||||
int16_t mma_buffer[2][SOUNDBUFLEN];
|
||||
|
||||
int pos;
|
||||
} adgold_t;
|
||||
|
||||
void adgold_update_irq_status(adgold_t *adgold)
|
||||
{
|
||||
uint8_t temp = 0xf;
|
||||
|
||||
if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/
|
||||
temp &= ~2;
|
||||
if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/
|
||||
temp &= ~2;
|
||||
if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/
|
||||
temp &= ~2;
|
||||
|
||||
if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2))
|
||||
temp &= ~2;
|
||||
if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2))
|
||||
temp &= ~2;
|
||||
adgold->adgold_status = temp;
|
||||
|
||||
if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status)
|
||||
{
|
||||
pclog("adgold irq %02X\n", adgold->adgold_status);
|
||||
picint(0x80);
|
||||
}
|
||||
|
||||
adgold->adgold_irq_status = adgold->adgold_status ^ 0xf;
|
||||
}
|
||||
|
||||
void adgold_getsamp_dma(adgold_t *adgold, int channel)
|
||||
{
|
||||
int temp;
|
||||
|
||||
if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127))
|
||||
return;
|
||||
|
||||
temp = readdma1();
|
||||
// pclog("adgold DMA1 return %02X %i L\n", temp, channel);
|
||||
if (temp == -1) return;
|
||||
adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp;
|
||||
adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255;
|
||||
if (adgold->adgold_mma_regs[channel][0xc] & 0x60)
|
||||
{
|
||||
temp = readdma1();
|
||||
// pclog("adgold DMA1 return %02X %i H\n", temp, channel);
|
||||
adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp;
|
||||
adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255;
|
||||
}
|
||||
if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~(0x01 << channel);
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
|
||||
void adgold_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc);
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 0: case 1:
|
||||
opl3_write(addr, val, &adgold->opl);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (val == 0xff)
|
||||
{
|
||||
adgold->adgold_38x_state = 1;
|
||||
return;
|
||||
}
|
||||
if (val == 0xfe)
|
||||
{
|
||||
adgold->adgold_38x_state = 0;
|
||||
return;
|
||||
}
|
||||
if (adgold->adgold_38x_state) /*Write to control chip*/
|
||||
adgold->adgold_38x_addr = val;
|
||||
else
|
||||
opl3_write(addr, val, &adgold->opl);
|
||||
break;
|
||||
case 3:
|
||||
if (adgold->adgold_38x_state)
|
||||
{
|
||||
if (adgold->adgold_38x_addr >= 0x19) break;
|
||||
switch (adgold->adgold_38x_addr)
|
||||
{
|
||||
case 0x00: /*Control/ID*/
|
||||
if (val & 1)
|
||||
memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19);
|
||||
if (val & 2)
|
||||
memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19);
|
||||
break;
|
||||
|
||||
default:
|
||||
adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
opl3_write(addr, val, &adgold->opl);
|
||||
break;
|
||||
case 4: case 6:
|
||||
adgold->adgold_mma_addr = val;
|
||||
break;
|
||||
case 5:
|
||||
if (adgold->adgold_mma_addr >= 0xf) break;
|
||||
switch (adgold->adgold_mma_addr)
|
||||
{
|
||||
case 0x2:
|
||||
adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val;
|
||||
break;
|
||||
case 0x3:
|
||||
adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8);
|
||||
break;
|
||||
case 0x4:
|
||||
adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val;
|
||||
break;
|
||||
case 0x5:
|
||||
adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8);
|
||||
adgold->adgold_mma.timer1_latch = val >> 4;
|
||||
break;
|
||||
case 0x6:
|
||||
adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val;
|
||||
break;
|
||||
case 0x7:
|
||||
adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/
|
||||
adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch;
|
||||
|
||||
if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/
|
||||
adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch;
|
||||
|
||||
if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/
|
||||
adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch;
|
||||
|
||||
if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/
|
||||
adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch;
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
switch (val & 0x18)
|
||||
{
|
||||
case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/
|
||||
case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/
|
||||
case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/
|
||||
case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/
|
||||
}
|
||||
if (val & 0x80)
|
||||
{
|
||||
adgold->adgold_mma_enable[0] = 0;
|
||||
adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0;
|
||||
adgold->adgold_mma_status &= ~0x01;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
if ((val & 0x01)) /*Start playback*/
|
||||
{
|
||||
if (!(adgold->adgold_mma_regs[0][0x9] & 1))
|
||||
adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0];
|
||||
|
||||
pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]);
|
||||
if (adgold->adgold_mma_regs[0][0xc] & 1)
|
||||
{
|
||||
if (adgold->adgold_mma_regs[0][0xc] & 0x80)
|
||||
{
|
||||
// pclog("adgold start interleaved %i %i
|
||||
adgold->adgold_mma_enable[1] = 1;
|
||||
adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
|
||||
|
||||
while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
|
||||
{
|
||||
adgold_getsamp_dma(adgold, 0);
|
||||
adgold_getsamp_dma(adgold, 1);
|
||||
}
|
||||
if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~0x01;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~0x02;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
|
||||
{
|
||||
adgold_getsamp_dma(adgold, 0);
|
||||
}
|
||||
if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~0x01;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
}
|
||||
pclog("adgold end\n");
|
||||
}
|
||||
adgold->adgold_mma_enable[0] = val & 0x01;
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
|
||||
{
|
||||
adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val;
|
||||
adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255;
|
||||
if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~0x01;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8;
|
||||
break;
|
||||
}
|
||||
adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val;
|
||||
break;
|
||||
case 7:
|
||||
if (adgold->adgold_mma_addr >= 0xf) break;
|
||||
switch (adgold->adgold_mma_addr)
|
||||
{
|
||||
case 0x9:
|
||||
switch (val & 0x18)
|
||||
{
|
||||
case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/
|
||||
case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/
|
||||
case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/
|
||||
case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/
|
||||
}
|
||||
if (val & 0x80)
|
||||
{
|
||||
adgold->adgold_mma_enable[1] = 0;
|
||||
adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0;
|
||||
adgold->adgold_mma_status &= ~0x02;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
if ((val & 0x01)) /*Start playback*/
|
||||
{
|
||||
if (!(adgold->adgold_mma_regs[1][0x9] & 1))
|
||||
adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
|
||||
|
||||
pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]);
|
||||
if (adgold->adgold_mma_regs[1][0xc] & 1)
|
||||
{
|
||||
while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128)
|
||||
{
|
||||
adgold_getsamp_dma(adgold, 1);
|
||||
}
|
||||
}
|
||||
pclog("adgold end\n");
|
||||
}
|
||||
adgold->adgold_mma_enable[1] = val & 0x01;
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128)
|
||||
{
|
||||
adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val;
|
||||
adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255;
|
||||
if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1])
|
||||
{
|
||||
adgold->adgold_mma_status &= ~0x02;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8;
|
||||
break;
|
||||
}
|
||||
adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t adgold_read(uint16_t addr, void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
uint8_t temp;
|
||||
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 0: case 1:
|
||||
temp = opl3_read(addr, &adgold->opl);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (adgold->adgold_38x_state) /*Read from control chip*/
|
||||
temp = adgold->adgold_status;
|
||||
else
|
||||
temp = opl3_read(addr, &adgold->opl);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (adgold->adgold_38x_state)
|
||||
{
|
||||
if (adgold->adgold_38x_addr >= 0x19) temp = 0xff;
|
||||
switch (adgold->adgold_38x_addr)
|
||||
{
|
||||
case 0x00: /*Control/ID*/
|
||||
temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/
|
||||
break;
|
||||
|
||||
default:
|
||||
temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr];
|
||||
}
|
||||
}
|
||||
else
|
||||
temp = opl3_read(addr, &adgold->opl);
|
||||
break;
|
||||
|
||||
case 4: case 6:
|
||||
temp = adgold->adgold_mma_status;
|
||||
adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/
|
||||
adgold_update_irq_status(adgold);
|
||||
break;
|
||||
case 5:
|
||||
if (adgold->adgold_mma_addr >= 0xf) temp = 0xff;
|
||||
switch (adgold->adgold_mma_addr)
|
||||
{
|
||||
case 6: /*Timer 2 low*/
|
||||
adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count;
|
||||
temp = adgold->adgold_mma.timer2_read & 0xff;
|
||||
break;
|
||||
case 7: /*Timer 2 high*/
|
||||
temp = adgold->adgold_mma.timer2_read >> 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (adgold->adgold_mma_addr >= 0xf) temp = 0xff;
|
||||
temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr];
|
||||
break;
|
||||
}
|
||||
if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void adgold_mma_poll(adgold_t *adgold, int channel)
|
||||
{
|
||||
int16_t dat;
|
||||
|
||||
if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel])
|
||||
{
|
||||
switch (adgold->adgold_mma_regs[channel][0xc] & 0x60)
|
||||
{
|
||||
case 0x00: /*8-bit*/
|
||||
dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256;
|
||||
adgold->adgold_mma_out[channel] = dat;
|
||||
adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
|
||||
break;
|
||||
|
||||
case 0x40: /*12-bit sensible format*/
|
||||
if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2)
|
||||
return;
|
||||
|
||||
dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0;
|
||||
adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
|
||||
dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8);
|
||||
adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
|
||||
adgold->adgold_mma_out[channel] = dat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (adgold->adgold_mma_regs[channel][0xc] & 1)
|
||||
{
|
||||
adgold_getsamp_dma(adgold, channel);
|
||||
}
|
||||
if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01))
|
||||
{
|
||||
// pclog("adgold_mma_poll - IRQ! %i\n", channel);
|
||||
adgold->adgold_mma_status |= 1 << channel;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel])
|
||||
{
|
||||
adgold->adgold_mma_enable[channel] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void adgold_timer_poll(void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
|
||||
while (adgold->adgold_mma_timer_count <= 0)
|
||||
{
|
||||
adgold->adgold_mma_timer_count += (int)((double)TIMER_USEC * 1.88964);
|
||||
if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/
|
||||
{
|
||||
adgold->adgold_mma.timer0_count--;
|
||||
if (!adgold->adgold_mma.timer0_count)
|
||||
{
|
||||
adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch;
|
||||
pclog("Timer 0 interrupt\n");
|
||||
adgold->adgold_mma_status |= 0x10;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/
|
||||
{
|
||||
adgold->adgold_mma.timerbase_count--;
|
||||
if (!adgold->adgold_mma.timerbase_count)
|
||||
{
|
||||
adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch;
|
||||
if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/
|
||||
{
|
||||
adgold->adgold_mma.timer1_count--;
|
||||
if (!adgold->adgold_mma.timer1_count)
|
||||
{
|
||||
adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch;
|
||||
pclog("Timer 1 interrupt\n");
|
||||
adgold->adgold_mma_status |= 0x20;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/
|
||||
{
|
||||
adgold->adgold_mma.timer2_count--;
|
||||
if (!adgold->adgold_mma.timer2_count)
|
||||
{
|
||||
adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch;
|
||||
pclog("Timer 2 interrupt\n");
|
||||
adgold->adgold_mma_status |= 0x40;
|
||||
adgold_update_irq_status(adgold);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adgold->adgold_mma_enable[0])
|
||||
{
|
||||
adgold->adgold_mma.voice_count[0]--;
|
||||
if (!adgold->adgold_mma.voice_count[0])
|
||||
{
|
||||
adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0];
|
||||
adgold_mma_poll(adgold, 0);
|
||||
}
|
||||
}
|
||||
if (adgold->adgold_mma_enable[1])
|
||||
{
|
||||
adgold->adgold_mma.voice_count[1]--;
|
||||
if (!adgold->adgold_mma.voice_count[1])
|
||||
{
|
||||
adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
|
||||
adgold_mma_poll(adgold, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adgold_poll(void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
|
||||
if (adgold->pos >= SOUNDBUFLEN)
|
||||
return;
|
||||
|
||||
opl3_poll(&adgold->opl, &adgold->opl_buffer[adgold->pos * 2], &adgold->opl_buffer[(adgold->pos * 2) + 1]);
|
||||
adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0;
|
||||
|
||||
if (adgold->adgold_mma_regs[0][9] & 0x20)
|
||||
adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2;
|
||||
if (adgold->adgold_mma_regs[0][9] & 0x40)
|
||||
adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2;
|
||||
|
||||
if (adgold->adgold_mma_regs[1][9] & 0x20)
|
||||
adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2;
|
||||
if (adgold->adgold_mma_regs[1][9] & 0x40)
|
||||
adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2;
|
||||
|
||||
adgold->pos++;
|
||||
}
|
||||
|
||||
static void adgold_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
{
|
||||
buffer[c] += adgold->opl_buffer[c];
|
||||
buffer[c] += adgold->mma_buffer[c & 1][c >> 1] / 2;
|
||||
}
|
||||
|
||||
adgold->pos = 0;
|
||||
}
|
||||
|
||||
|
||||
void *adgold_init()
|
||||
{
|
||||
adgold_t *adgold = malloc(sizeof(adgold_t));
|
||||
memset(adgold, 0, sizeof(adgold_t));
|
||||
|
||||
opl3_init(&adgold->opl);
|
||||
|
||||
adgold->adgold_status = 0xf;
|
||||
adgold->adgold_38x_addr = 0;
|
||||
adgold->adgold_eeprom[0x09] = adgold->adgold_eeprom[0x0a] = 255;
|
||||
adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/
|
||||
adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/
|
||||
adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/
|
||||
memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19);
|
||||
|
||||
adgold->adgold_mma_enable[0] = 0;
|
||||
adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0;
|
||||
|
||||
/*388/389 are handled by adlib_init*/
|
||||
io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold);
|
||||
|
||||
timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold);
|
||||
|
||||
sound_add_handler(adgold_poll, adgold_get_buffer, adgold);
|
||||
|
||||
return adgold;
|
||||
}
|
||||
|
||||
void adgold_close(void *p)
|
||||
{
|
||||
adgold_t *adgold = (adgold_t *)p;
|
||||
|
||||
free(adgold);
|
||||
}
|
||||
|
||||
device_t adgold_device =
|
||||
{
|
||||
"AdLib Gold",
|
||||
adgold_init,
|
||||
adgold_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_adlibgold.h
Normal file
1
src/sound_adlibgold.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t adgold_device;
|
||||
179
src/sound_cms.c
Normal file
179
src/sound_cms.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "io.h"
|
||||
#include "sound.h"
|
||||
#include "sound_cms.h"
|
||||
|
||||
typedef struct cms_t
|
||||
{
|
||||
int addrs[2];
|
||||
uint8_t regs[2][32];
|
||||
uint16_t latch[2][6];
|
||||
int freq[2][6];
|
||||
float count[2][6];
|
||||
int vol[2][6][2];
|
||||
int stat[2][6];
|
||||
uint16_t noise[2][2];
|
||||
uint16_t noisefreq[2][2];
|
||||
int noisecount[2][2];
|
||||
int noisetype[2][2];
|
||||
|
||||
int16_t buffer[SOUNDBUFLEN * 2];
|
||||
|
||||
int pos;
|
||||
} cms_t;
|
||||
|
||||
void cms_poll(void *p)
|
||||
{
|
||||
cms_t *cms = (cms_t *)p;
|
||||
int c, d;
|
||||
int16_t out_l = 0, out_r = 0;
|
||||
|
||||
if (cms->pos >= SOUNDBUFLEN)
|
||||
return;
|
||||
|
||||
for (c = 0; c < 4; c++)
|
||||
{
|
||||
switch (cms->noisetype[c >> 1][c & 1])
|
||||
{
|
||||
case 0: cms->noisefreq[c >> 1][c & 1] = 31250; break;
|
||||
case 1: cms->noisefreq[c >> 1][c & 1] = 15625; break;
|
||||
case 2: cms->noisefreq[c >> 1][c & 1] = 7812; break;
|
||||
case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break;
|
||||
}
|
||||
}
|
||||
for (c = 0; c < 2; c ++)
|
||||
{
|
||||
if (cms->regs[c][0x1C] & 1)
|
||||
{
|
||||
for (d = 0; d < 6; d++)
|
||||
{
|
||||
if (cms->regs[c][0x14] & (1 << d))
|
||||
{
|
||||
if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90);
|
||||
if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90);
|
||||
cms->count[c][d] += cms->freq[c][d];
|
||||
if (cms->count[c][d] >= 24000)
|
||||
{
|
||||
cms->count[c][d] -= 24000;
|
||||
cms->stat[c][d] ^= 1;
|
||||
}
|
||||
}
|
||||
else if (cms->regs[c][0x15] & (1 << d))
|
||||
{
|
||||
if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90);
|
||||
if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90);
|
||||
}
|
||||
}
|
||||
for (d = 0; d < 2; d++)
|
||||
{
|
||||
cms->noisecount[c][d] += cms->noisefreq[c][d];
|
||||
while (cms->noisecount[c][d] >= 24000)
|
||||
{
|
||||
cms->noisecount[c][d] -= 24000;
|
||||
cms->noise[c][d] <<= 1;
|
||||
if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40)))
|
||||
cms->noise[c][d] |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cms->buffer[(cms->pos << 1)] = out_l;
|
||||
cms->buffer[(cms->pos << 1) + 1] = out_r;
|
||||
|
||||
cms->pos++;
|
||||
}
|
||||
|
||||
void cms_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
cms_t *cms = (cms_t *)p;
|
||||
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
buffer[c] += cms->buffer[c];
|
||||
|
||||
cms->pos = 0;
|
||||
}
|
||||
|
||||
void cms_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
cms_t *cms = (cms_t *)p;
|
||||
int voice;
|
||||
int chip = (addr & 2) >> 1;
|
||||
|
||||
pclog("cms_write : addr %04X val %02X\n", addr, val);
|
||||
|
||||
if (addr & 1)
|
||||
cms->addrs[chip] = val & 31;
|
||||
else
|
||||
{
|
||||
cms->regs[chip][cms->addrs[chip] & 31] = val;
|
||||
switch (cms->addrs[chip] & 31)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: /*Volume*/
|
||||
case 0x03: case 0x04: case 0x05:
|
||||
voice = cms->addrs[chip] & 7;
|
||||
cms->vol[chip][voice][0] = val & 0xf;
|
||||
cms->vol[chip][voice][1] = val >> 4;
|
||||
break;
|
||||
case 0x08: case 0x09: case 0x0A: /*Frequency*/
|
||||
case 0x0B: case 0x0C: case 0x0D:
|
||||
voice = cms->addrs[chip] & 7;
|
||||
cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val;
|
||||
cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255));
|
||||
break;
|
||||
case 0x10: case 0x11: case 0x12: /*Octave*/
|
||||
voice = (cms->addrs[chip] & 3) << 1;
|
||||
cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8);
|
||||
cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4);
|
||||
cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255));
|
||||
cms->freq[chip][voice + 1] = (15625 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255));
|
||||
break;
|
||||
case 0x16: /*Noise*/
|
||||
cms->noisetype[chip][0] = val & 3;
|
||||
cms->noisetype[chip][1] = (val >> 4) & 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t cms_read(uint16_t addr, void *p)
|
||||
{
|
||||
cms_t *cms = (cms_t *)p;
|
||||
int chip = (addr & 2) >> 1;
|
||||
|
||||
if (addr & 1)
|
||||
return cms->addrs[chip];
|
||||
|
||||
return cms->regs[chip][cms->addrs[chip] & 31];
|
||||
}
|
||||
|
||||
void *cms_init()
|
||||
{
|
||||
cms_t *cms = malloc(sizeof(cms_t));
|
||||
memset(cms, 0, sizeof(cms_t));
|
||||
|
||||
pclog("cms_init\n");
|
||||
io_sethandler(0x0220, 0x0004, cms_read, NULL, NULL, cms_write, NULL, NULL, cms);
|
||||
sound_add_handler(cms_poll, cms_get_buffer, cms);
|
||||
return cms;
|
||||
}
|
||||
|
||||
void cms_close(void *p)
|
||||
{
|
||||
cms_t *cms = (cms_t *)p;
|
||||
|
||||
free(cms);
|
||||
}
|
||||
|
||||
device_t cms_device =
|
||||
{
|
||||
"Creative Music System / Game Blaster",
|
||||
cms_init,
|
||||
cms_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_cms.h
Normal file
1
src/sound_cms.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t cms_device;
|
||||
1107
src/sound_gus.c
Normal file
1107
src/sound_gus.c
Normal file
File diff suppressed because it is too large
Load diff
1
src/sound_gus.h
Normal file
1
src/sound_gus.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t gus_device;
|
||||
195
src/sound_opl.c
Normal file
195
src/sound_opl.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "sound_opl.h"
|
||||
|
||||
/*Interfaces between PCem and the actual OPL emulator*/
|
||||
|
||||
|
||||
uint8_t opl2_read(uint16_t a, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[0], a);
|
||||
}
|
||||
void opl2_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[0],a,v);
|
||||
ym3812_write(opl->YM3812[1],a,v);
|
||||
}
|
||||
|
||||
uint8_t opl2_l_read(uint16_t a, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[0], a);
|
||||
}
|
||||
void opl2_l_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[0],a,v);
|
||||
}
|
||||
|
||||
uint8_t opl2_r_read(uint16_t a, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ym3812_read(opl->YM3812[1], a);
|
||||
}
|
||||
void opl2_r_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ym3812_write(opl->YM3812[1],a,v);
|
||||
}
|
||||
|
||||
uint8_t opl3_read(uint16_t a, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
cycles -= (int)(isa_timing * 8);
|
||||
return ymf262_read(opl->YMF262, a);
|
||||
}
|
||||
void opl3_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
opl_t *opl = (opl_t *)priv;
|
||||
|
||||
ymf262_write(opl->YMF262, a, v);
|
||||
}
|
||||
|
||||
|
||||
void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
||||
{
|
||||
ym3812_update_one(opl->YM3812[0], bufl, 1);
|
||||
ym3812_update_one(opl->YM3812[1], bufr, 1);
|
||||
|
||||
opl->filtbuf[0] = *bufl = ((*bufl) / 4) + ((opl->filtbuf[0] * 11) / 16);
|
||||
opl->filtbuf[1] = *bufr = ((*bufr) / 4) + ((opl->filtbuf[1] * 11) / 16);
|
||||
|
||||
if (opl->timers_enable[0][0])
|
||||
{
|
||||
opl->timers[0][0]--;
|
||||
if (opl->timers[0][0] < 0) ym3812_timer_over(opl->YM3812[0], 0);
|
||||
}
|
||||
if (opl->timers_enable[0][1])
|
||||
{
|
||||
opl->timers[0][1]--;
|
||||
if (opl->timers[0][1] < 0) ym3812_timer_over(opl->YM3812[0], 1);
|
||||
}
|
||||
if (opl->timers_enable[1][0])
|
||||
{
|
||||
opl->timers[1][0]--;
|
||||
if (opl->timers[1][0] < 0) ym3812_timer_over(opl->YM3812[1], 0);
|
||||
}
|
||||
if (opl->timers_enable[1][1])
|
||||
{
|
||||
opl->timers[1][1]--;
|
||||
if (opl->timers[1][1] < 0) ym3812_timer_over(opl->YM3812[1], 1);
|
||||
}
|
||||
}
|
||||
|
||||
void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr)
|
||||
{
|
||||
ymf262_update_one(opl->YMF262, opl->bufs, 1);
|
||||
|
||||
opl->filtbuf[0] = *bufl = ((opl->bufs[0][0]) / 4) + ((opl->filtbuf[0] * 11) / 16);
|
||||
opl->filtbuf[1] = *bufr = ((opl->bufs[1][0]) / 4) + ((opl->filtbuf[1] * 11) / 16);
|
||||
|
||||
if (opl->timers_enable[0][0])
|
||||
{
|
||||
opl->timers[0][0]--;
|
||||
if (opl->timers[0][0] < 0)
|
||||
{
|
||||
opl->timers_enable[0][0] = 0;
|
||||
ymf262_timer_over(opl->YMF262, 0);
|
||||
}
|
||||
}
|
||||
if (opl->timers_enable[0][1])
|
||||
{
|
||||
opl->timers[0][1]--;
|
||||
if (opl->timers[0][1] < 0)
|
||||
{
|
||||
opl->timers_enable[0][1] = 0;
|
||||
ymf262_timer_over(opl->YMF262, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ym3812_timer_set_0(void *param, int timer, attotime period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
opl->timers[0][timer] = period / 20833;
|
||||
if (!opl->timers[0][timer]) opl->timers[0][timer] = 1;
|
||||
opl->timers_enable[0][timer] = period ? 1 : 0;
|
||||
}
|
||||
void ym3812_timer_set_1(void *param, int timer, attotime period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
opl->timers[1][timer] = period / 20833;
|
||||
if (!opl->timers[1][timer]) opl->timers[1][timer] = 1;
|
||||
opl->timers_enable[1][timer] = period ? 1 : 0;
|
||||
}
|
||||
|
||||
void ymf262_timer_set(void *param, int timer, attotime period)
|
||||
{
|
||||
opl_t *opl = (opl_t *)param;
|
||||
|
||||
opl->timers[0][timer] = period / 20833;
|
||||
if (!opl->timers[0][timer]) opl->timers[0][timer] = 1;
|
||||
opl->timers_enable[0][timer] = period ? 1 : 0;
|
||||
}
|
||||
|
||||
void opl2_init(opl_t *opl)
|
||||
{
|
||||
opl->bufs[0] = (int16_t *)malloc(4);
|
||||
opl->bufs[1] = (int16_t *)malloc(4);
|
||||
opl->bufs[2] = (int16_t *)malloc(4);
|
||||
opl->bufs[3] = (int16_t *)malloc(4);
|
||||
|
||||
opl->YM3812[0] = ym3812_init(NULL, 3579545, 48000);
|
||||
ym3812_reset_chip(opl->YM3812[0]);
|
||||
ym3812_set_timer_handler(opl->YM3812[0], ym3812_timer_set_0, opl);
|
||||
|
||||
opl->YM3812[1] = ym3812_init(NULL, 3579545, 48000);
|
||||
ym3812_reset_chip(opl->YM3812[1]);
|
||||
ym3812_set_timer_handler(opl->YM3812[1], ym3812_timer_set_1, opl);
|
||||
}
|
||||
|
||||
void opl3_init(opl_t *opl)
|
||||
{
|
||||
opl->bufs[0] = (int16_t *)malloc(4);
|
||||
opl->bufs[1] = (int16_t *)malloc(4);
|
||||
opl->bufs[2] = (int16_t *)malloc(4);
|
||||
opl->bufs[3] = (int16_t *)malloc(4);
|
||||
|
||||
opl->YMF262 = ymf262_init(NULL, 3579545 * 4, 48000);
|
||||
ymf262_reset_chip(opl->YMF262);
|
||||
ymf262_set_timer_handler(opl->YMF262, ymf262_timer_set, opl);
|
||||
}
|
||||
|
||||
void opl2_close(opl_t *opl)
|
||||
{
|
||||
free(opl->bufs[0]);
|
||||
free(opl->bufs[1]);
|
||||
|
||||
ym3812_shutdown(opl->YM3812[0]);
|
||||
ym3812_shutdown(opl->YM3812[1]);
|
||||
}
|
||||
|
||||
void opl3_close(opl_t *opl)
|
||||
{
|
||||
free(opl->bufs[0]);
|
||||
free(opl->bufs[1]);
|
||||
|
||||
ym3812_shutdown(opl->YM3812[0]);
|
||||
ymf262_shutdown(opl->YMF262);
|
||||
}
|
||||
35
src/sound_opl.h
Normal file
35
src/sound_opl.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "mame/fmopl.h"
|
||||
#include "mame/ymf262.h"
|
||||
|
||||
typedef struct opl_t
|
||||
{
|
||||
void *YM3812[2];
|
||||
void *YMF262;
|
||||
|
||||
int timers[2][2];
|
||||
int timers_enable[2][2];
|
||||
|
||||
int16_t *bufs[4];
|
||||
int16_t filtbuf[2];
|
||||
} opl_t;
|
||||
|
||||
uint8_t opl_read(uint16_t a, void *priv);
|
||||
void opl_write(uint16_t a, uint8_t v, void *priv);
|
||||
|
||||
uint8_t opl2_read(uint16_t a, void *priv);
|
||||
void opl2_write(uint16_t a, uint8_t v, void *priv);
|
||||
uint8_t opl2_l_read(uint16_t a, void *priv);
|
||||
void opl2_l_write(uint16_t a, uint8_t v, void *priv);
|
||||
uint8_t opl2_r_read(uint16_t a, void *priv);
|
||||
void opl2_r_write(uint16_t a, uint8_t v, void *priv);
|
||||
uint8_t opl3_read(uint16_t a, void *priv);
|
||||
void opl3_write(uint16_t a, uint8_t v, void *priv);
|
||||
|
||||
void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr);
|
||||
void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr);
|
||||
|
||||
void opl2_init(opl_t *opl);
|
||||
void opl3_init(opl_t *opl);
|
||||
|
||||
void opl2_close(opl_t *opl);
|
||||
void opl3_close(opl_t *opl);
|
||||
753
src/sound_pas16.c
Normal file
753
src/sound_pas16.c
Normal file
|
|
@ -0,0 +1,753 @@
|
|||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "dma.h"
|
||||
#include "filters.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "sound_opl.h"
|
||||
#include "sound_pas16.h"
|
||||
#include "sound_sb_dsp.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Original PAS uses
|
||||
2 x OPL2
|
||||
PIT - sample rate/count
|
||||
LMC835N/LMC1982 - mixer
|
||||
YM3802 - MIDI Control System
|
||||
|
||||
|
||||
9A01 - IO base
|
||||
base >> 2
|
||||
|
||||
All below + IO base
|
||||
|
||||
B89 - interrupt status / clear
|
||||
bit 2 - sample rate
|
||||
bit 3 - PCM
|
||||
bit 4 - MIDI
|
||||
|
||||
B88 - Audio mixer control register
|
||||
|
||||
B8A - Audio filter control
|
||||
bit 5 - mute?
|
||||
|
||||
B8B - interrupt mask / board ID
|
||||
bits 5-7 - board ID (read only on PAS16)
|
||||
|
||||
F88 - PCM data (low)
|
||||
|
||||
F89 - PCM data (high)
|
||||
|
||||
F8A - PCM control?
|
||||
bit 4 - input/output select (1 = output)
|
||||
bit 5 - mono/stereo select
|
||||
bit 6 - PCM enable
|
||||
|
||||
1388-138b - PIT clocked at 1193180 Hz
|
||||
1388 - sample rate
|
||||
1389 - sample count
|
||||
|
||||
178b -
|
||||
2789 - board revision
|
||||
|
||||
8389 -
|
||||
bit 2 - 8/16 bit
|
||||
|
||||
BF88 - wait states
|
||||
|
||||
EF8B -
|
||||
bit 3 - 16 bits okay ?
|
||||
|
||||
F388 -
|
||||
bit 6 - joystick enable
|
||||
|
||||
F389 -
|
||||
bits 0-2 - DMA
|
||||
|
||||
F38A -
|
||||
bits 0-3 - IRQ
|
||||
|
||||
F788 -
|
||||
bit 1 - SB emulation
|
||||
bit 0 - MPU401 emulation
|
||||
|
||||
F789 - SB base addr
|
||||
bits 0-3 - addr bits 4-7
|
||||
|
||||
FB8A - SB IRQ/DMA
|
||||
bits 3-5 - IRQ
|
||||
bits 6-7 - DMA
|
||||
|
||||
FF88 - board model
|
||||
3 = PAS16
|
||||
*/
|
||||
|
||||
static uint8_t pas16_pit_in(uint16_t port, void *priv);
|
||||
static void pas16_pit_out(uint16_t port, uint8_t val, void *priv);
|
||||
//static void pas16_update_irqs();
|
||||
|
||||
typedef struct pas16_t
|
||||
{
|
||||
uint16_t base;
|
||||
|
||||
int irq, dma;
|
||||
|
||||
uint8_t audiofilt;
|
||||
|
||||
uint8_t audio_mixer;
|
||||
|
||||
uint8_t compat, compat_base;
|
||||
|
||||
uint8_t enhancedscsi;
|
||||
|
||||
uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4;
|
||||
|
||||
uint8_t irq_stat, irq_ena;
|
||||
|
||||
uint8_t pcm_ctrl;
|
||||
uint16_t pcm_dat;
|
||||
|
||||
uint16_t pcm_dat_l, pcm_dat_r;
|
||||
|
||||
uint8_t sb_irqdma;
|
||||
|
||||
int stereo_lr;
|
||||
|
||||
uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t l[3];
|
||||
int c[3];
|
||||
uint8_t m[3];
|
||||
uint8_t ctrl, ctrls[2];
|
||||
int wp, rm[3], wm[3];
|
||||
uint16_t rl[3];
|
||||
int thit[3];
|
||||
int delay[3];
|
||||
int rereadlatch[3];
|
||||
int enable[3];
|
||||
} pit;
|
||||
|
||||
opl_t opl;
|
||||
sb_dsp_t dsp;
|
||||
|
||||
int16_t opl_buffer[SOUNDBUFLEN * 2];
|
||||
int16_t pcm_buffer[2][SOUNDBUFLEN];
|
||||
int16_t dsp_buffer[SOUNDBUFLEN * 2];
|
||||
|
||||
int pos;
|
||||
} pas16_t;
|
||||
|
||||
static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7};
|
||||
static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0};
|
||||
static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12};
|
||||
static int pas16_sb_dmas[8] = {0, 1, 2, 3};
|
||||
|
||||
enum
|
||||
{
|
||||
PAS16_INT_SAMP = 0x04,
|
||||
PAS16_INT_PCM = 0x08,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PAS16_PCM_MONO = 0x20,
|
||||
PAS16_PCM_ENA = 0x40
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PAS16_SC2_16BIT = 0x04,
|
||||
PAS16_SC2_MSBINV = 0x10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PAS16_FILT_MUTE = 0x20
|
||||
};
|
||||
|
||||
static uint8_t pas16_in(uint16_t port, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
uint8_t temp;
|
||||
/* if (CS == 0xCA53 && pc == 0x3AFC)
|
||||
fatal("here");*/
|
||||
switch ((port - pas16->base) + 0x388)
|
||||
{
|
||||
case 0x388: case 0x389: case 0x38a: case 0x38b:
|
||||
temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl);
|
||||
break;
|
||||
|
||||
case 0xb88:
|
||||
temp = pas16->audio_mixer;
|
||||
break;
|
||||
|
||||
case 0xb89:
|
||||
temp = pas16->irq_stat;
|
||||
break;
|
||||
|
||||
case 0xb8a:
|
||||
temp = pas16->audiofilt;
|
||||
break;
|
||||
|
||||
case 0xb8b:
|
||||
temp = (pas16->irq_ena & ~0xe0) | 0x20;
|
||||
break;
|
||||
|
||||
case 0xf8a:
|
||||
temp = pas16->pcm_ctrl;
|
||||
break;
|
||||
|
||||
case 0x1388: case 0x1389: case 0x138a: case 0x138b:
|
||||
temp = pas16_pit_in(port, pas16);
|
||||
break;
|
||||
|
||||
case 0x2789: /*Board revision*/
|
||||
temp = 0;
|
||||
break;
|
||||
|
||||
case 0x7f89:
|
||||
temp = pas16->enhancedscsi & ~1;
|
||||
break;
|
||||
|
||||
case 0x8388:
|
||||
temp = pas16->sys_conf_1;
|
||||
break;
|
||||
case 0x8389:
|
||||
temp = pas16->sys_conf_2;
|
||||
break;
|
||||
case 0x838b:
|
||||
temp = pas16->sys_conf_3;
|
||||
break;
|
||||
case 0x838c:
|
||||
temp = pas16->sys_conf_4;
|
||||
break;
|
||||
|
||||
case 0xef8b:
|
||||
temp = 0x0c;
|
||||
break;
|
||||
|
||||
case 0xf388:
|
||||
temp = pas16->io_conf_1;
|
||||
break;
|
||||
case 0xf389:
|
||||
temp = pas16->io_conf_2;
|
||||
break;
|
||||
case 0xf38b:
|
||||
temp = pas16->io_conf_3;
|
||||
break;
|
||||
case 0xf38c:
|
||||
temp = pas16->io_conf_4;
|
||||
break;
|
||||
|
||||
case 0xf788:
|
||||
temp = pas16->compat;
|
||||
break;
|
||||
case 0xf789:
|
||||
temp = pas16->compat_base;
|
||||
break;
|
||||
|
||||
case 0xfb8a:
|
||||
temp = pas16->sb_irqdma;
|
||||
break;
|
||||
|
||||
case 0xff88: /*Board model*/
|
||||
temp = 4; /*PAS16*/
|
||||
break;
|
||||
case 0xff8b: /*Master mode read*/
|
||||
temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/
|
||||
break;
|
||||
}
|
||||
/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pclog("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,pc);
|
||||
/* if (CS == 0x1FF4 && pc == 0x0585)
|
||||
{
|
||||
if (output)
|
||||
fatal("here");
|
||||
output = 3;
|
||||
}*/
|
||||
return temp;
|
||||
}
|
||||
|
||||
static void pas16_out(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
/* if (port != 0x388 && port != 0x389) */pclog("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,pc);
|
||||
/* if (CS == 0x369 && pc == 0x2AC5)
|
||||
fatal("here\n");*/
|
||||
switch ((port - pas16->base) + 0x388)
|
||||
{
|
||||
case 0x388: case 0x389: case 0x38a: case 0x38b:
|
||||
opl3_write((port - pas16->base) + 0x388, val, &pas16->opl);
|
||||
break;
|
||||
|
||||
case 0xb88:
|
||||
pas16->audio_mixer = val;
|
||||
break;
|
||||
|
||||
case 0xb89:
|
||||
pas16->irq_stat &= ~val;
|
||||
// pas16_update_irqs();
|
||||
break;
|
||||
|
||||
case 0xb8a:
|
||||
pas16->audiofilt = val;
|
||||
break;
|
||||
|
||||
case 0xb8b:
|
||||
pas16->irq_ena = val;
|
||||
// pas16_update_irqs();
|
||||
break;
|
||||
|
||||
case 0xf88:
|
||||
pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val;
|
||||
break;
|
||||
case 0xf89:
|
||||
pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8);
|
||||
break;
|
||||
case 0xf8a:
|
||||
if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/
|
||||
pas16->stereo_lr = 0;
|
||||
pas16->pcm_ctrl = val;
|
||||
break;
|
||||
|
||||
case 0x1388: case 0x1389: case 0x138a: case 0x138b:
|
||||
pas16_pit_out(port, val, pas16);
|
||||
break;
|
||||
|
||||
case 0x7f89:
|
||||
pas16->enhancedscsi = val;
|
||||
break;
|
||||
|
||||
case 0x8388:
|
||||
pas16->sys_conf_1 = val;
|
||||
break;
|
||||
case 0x8389:
|
||||
pas16->sys_conf_2 = val;
|
||||
break;
|
||||
case 0x838a:
|
||||
pas16->sys_conf_3 = val;
|
||||
break;
|
||||
case 0x838b:
|
||||
pas16->sys_conf_4 = val;
|
||||
break;
|
||||
|
||||
case 0xf388:
|
||||
pas16->io_conf_1 = val;
|
||||
break;
|
||||
case 0xf389:
|
||||
pas16->io_conf_2 = val;
|
||||
pas16->dma = pas16_dmas[val & 0x7];
|
||||
pclog("pas16_out : set PAS DMA %i\n", pas16->dma);
|
||||
break;
|
||||
case 0xf38a:
|
||||
pas16->io_conf_3 = val;
|
||||
pas16->irq = pas16_irqs[val & 0xf];
|
||||
pclog("pas16_out : set PAS IRQ %i\n", pas16->irq);
|
||||
break;
|
||||
case 0xf38b:
|
||||
pas16->io_conf_4 = val;
|
||||
break;
|
||||
|
||||
case 0xf788:
|
||||
pas16->compat = val;
|
||||
if (pas16->compat & 0x02)
|
||||
sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200);
|
||||
else
|
||||
sb_dsp_setaddr(&pas16->dsp, 0);
|
||||
break;
|
||||
case 0xf789:
|
||||
pas16->compat_base = val;
|
||||
if (pas16->compat & 0x02)
|
||||
sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200);
|
||||
break;
|
||||
|
||||
case 0xfb8a:
|
||||
pas16->sb_irqdma = val;
|
||||
sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]);
|
||||
sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]);
|
||||
pclog("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("pas16_out : unknown %04X\n", port);
|
||||
}
|
||||
if (pc == 0x80048CF3)
|
||||
{
|
||||
if (output)
|
||||
fatal("here\n");
|
||||
output = 3;
|
||||
}
|
||||
/* if (CS == 0x1FF4 && pc == 0x0431)
|
||||
output = 3;*/
|
||||
}
|
||||
|
||||
static void pas16_pit_out(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
int t;
|
||||
switch (port & 3)
|
||||
{
|
||||
case 3: /*CTRL*/
|
||||
if ((val & 0xC0) == 0xC0)
|
||||
{
|
||||
if (!(val & 0x20))
|
||||
{
|
||||
if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT));
|
||||
if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1];
|
||||
if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2];
|
||||
}
|
||||
return;
|
||||
}
|
||||
t = val >> 6;
|
||||
pas16->pit.ctrls[t] = pas16->pit.ctrl = val;
|
||||
if (t == 3)
|
||||
{
|
||||
printf("Bad PIT reg select\n");
|
||||
return;
|
||||
}
|
||||
if (!(pas16->pit.ctrl & 0x30))
|
||||
{
|
||||
pas16->pit.rl[t] = pas16->pit.c[t];
|
||||
if (!t)
|
||||
pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT));
|
||||
if (pas16->pit.c[t] < 0)
|
||||
pas16->pit.rl[t] = 0;
|
||||
pas16->pit.ctrl |= 0x30;
|
||||
pas16->pit.rereadlatch[t] = 0;
|
||||
pas16->pit.rm[t] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3;
|
||||
pas16->pit.m[t] = (val >> 1) & 7;
|
||||
if (pas16->pit.m[t] > 5)
|
||||
pas16->pit.m[t] &= 3;
|
||||
if (!pas16->pit.rm[t])
|
||||
{
|
||||
pas16->pit.rm[t] = 3;
|
||||
pas16->pit.rl[t] = pit.c[t];
|
||||
if (!t)
|
||||
pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT));
|
||||
}
|
||||
pas16->pit.rereadlatch[t] = 1;
|
||||
}
|
||||
pas16->pit.wp = 0;
|
||||
pas16->pit.thit[t] = 0;
|
||||
break;
|
||||
case 0: case 1: case 2: /*Timers*/
|
||||
t = port & 3;
|
||||
switch (pas16->pit.wm[t])
|
||||
{
|
||||
case 1:
|
||||
pas16->pit.l[t] = val;
|
||||
pas16->pit.thit[t] = 0;
|
||||
pas16->pit.c[t] = pas16->pit.l[t];
|
||||
if (!t)
|
||||
pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT);
|
||||
pas16->pit.enable[t] = 1;
|
||||
break;
|
||||
case 2:
|
||||
pas16->pit.l[t] = val << 8;
|
||||
pas16->pit.thit[t] = 0;
|
||||
pas16->pit.c[t] = pas16->pit.l[t];
|
||||
if (!t)
|
||||
pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT);
|
||||
pas16->pit.enable[t] = 1;
|
||||
break;
|
||||
case 0:
|
||||
pas16->pit.l[t] &= 0xFF;
|
||||
pas16->pit.l[t] |= (val << 8);
|
||||
pas16->pit.c[t] = pas16->pit.l[t];
|
||||
if (!t)
|
||||
pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT);
|
||||
pas16->pit.thit[t] = 0;
|
||||
pas16->pit.wm[t] = 3;
|
||||
pas16->pit.enable[t] = 1;
|
||||
break;
|
||||
case 3:
|
||||
pas16->pit.l[t] &= 0xFF00;
|
||||
pas16->pit.l[t] |= val;
|
||||
pas16->pit.wm[t] = 0;
|
||||
break;
|
||||
}
|
||||
if (!pas16->pit.l[t])
|
||||
{
|
||||
pas16->pit.l[t] |= 0x10000;
|
||||
pas16->pit.c[t] = pas16->pit.l[t];
|
||||
if (!t)
|
||||
pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t pas16_pit_in(uint16_t port, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
uint8_t temp;
|
||||
int t = port & 3;
|
||||
// printf("Read PIT %04X ",addr);
|
||||
switch (port & 3)
|
||||
{
|
||||
case 0: case 1: case 2: /*Timers*/
|
||||
if (pas16->pit.rereadlatch[t])
|
||||
{
|
||||
pas16->pit.rereadlatch[t] = 0;
|
||||
if (!t)
|
||||
{
|
||||
pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT));
|
||||
if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536)
|
||||
pas16->pit.rl[t] = 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas16->pit.rl[t] = pas16->pit.c[t];
|
||||
if (pas16->pit.c[t] > 65536)
|
||||
pas16->pit.rl[t] = 0xFFFF;
|
||||
}
|
||||
}
|
||||
switch (pas16->pit.rm[t])
|
||||
{
|
||||
case 0:
|
||||
temp = pas16->pit.rl[t] >> 8;
|
||||
pas16->pit.rm[t] = 3;
|
||||
pas16->pit.rereadlatch[t] = 1;
|
||||
break;
|
||||
case 1:
|
||||
temp = (pas16->pit.rl[t]) & 0xFF;
|
||||
pas16->pit.rereadlatch[t] = 1;
|
||||
break;
|
||||
case 2:
|
||||
temp = (pas16->pit.rl[t]) >> 8;
|
||||
pas16->pit.rereadlatch[t] = 1;
|
||||
break;
|
||||
case 3:
|
||||
temp = (pas16->pit.rl[t]) & 0xFF;
|
||||
if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7;
|
||||
else pas16->pit.rm[t] = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: /*Control*/
|
||||
temp = pas16->pit.ctrl;
|
||||
break;
|
||||
}
|
||||
// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static uint8_t pas16_readdma(pas16_t *pas16)
|
||||
{
|
||||
return dma_channel_read(pas16->dma);
|
||||
}
|
||||
|
||||
static void pas16_pcm_poll(void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
// if (pas16->pcm_ctrl & PAS16_PCM_ENA)
|
||||
// pclog("pas16_pcm_poll : poll %i %i ", pas16->pit.c[0], pas16->pit.l[0]);
|
||||
if (pas16->pit.m[0] & 2)
|
||||
{
|
||||
if (pas16->pit.l[0])
|
||||
pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT));
|
||||
else
|
||||
pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT));
|
||||
}
|
||||
else
|
||||
{
|
||||
pas16->pit.c[0] = -1;
|
||||
pas16->pit.enable[0] = 0;
|
||||
}
|
||||
// if (pas16->pcm_ctrl & PAS16_PCM_ENA)
|
||||
// pclog(" %i\n", pas16->pit.c[0]);
|
||||
|
||||
pas16->irq_stat |= PAS16_INT_SAMP;
|
||||
if (pas16->irq_ena & PAS16_INT_SAMP)
|
||||
picint(1 << pas16->irq);
|
||||
// pas16_update_irqs();
|
||||
|
||||
/*Update sample rate counter*/
|
||||
if (pas16->pit.enable[1])
|
||||
{
|
||||
if (pas16->pcm_ctrl & PAS16_PCM_ENA)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
if (pas16->sys_conf_2 & PAS16_SC2_16BIT)
|
||||
{
|
||||
temp = pas16_readdma(pas16) << 8;
|
||||
temp |= pas16_readdma(pas16);
|
||||
}
|
||||
else
|
||||
temp = (pas16_readdma(pas16) ^ 0x80) << 8;
|
||||
|
||||
if (pas16->sys_conf_2 & PAS16_SC2_MSBINV)
|
||||
temp ^= 0x8000;
|
||||
if (pas16->pcm_ctrl & PAS16_PCM_MONO)
|
||||
pas16->pcm_dat_l = pas16->pcm_dat_r = temp;
|
||||
else
|
||||
{
|
||||
if (pas16->stereo_lr)
|
||||
pas16->pcm_dat_r = temp;
|
||||
else
|
||||
pas16->pcm_dat_l = temp;
|
||||
|
||||
pas16->stereo_lr = !pas16->stereo_lr;
|
||||
}
|
||||
// pclog("pas16_pcm_poll : %04X %i\n", temp, pas16->stereo_lr);
|
||||
// pclog("pas16_pcm_poll : %i %02X %i\n", pas16->pit.c[1], temp, pas16->pit.c[0]);
|
||||
/* if (!pas16_pcm)
|
||||
pas16_pcm=fopen("pas16->pcm", "wb");
|
||||
putc(temp, pas16_pcm);*/
|
||||
}
|
||||
if (pas16->sys_conf_2 & PAS16_SC2_16BIT)
|
||||
pas16->pit.c[1] -= 2;
|
||||
else
|
||||
pas16->pit.c[1]--;
|
||||
if (pas16->pit.c[1] == 0)
|
||||
{
|
||||
// if (pas16->pcm_ctrl & PAS16_PCM_ENA)
|
||||
// pclog("pas16_pcm_poll : buffer over\n");
|
||||
if (pas16->pit.m[1] & 2)
|
||||
{
|
||||
if (pas16->pit.l[1])
|
||||
pas16->pit.c[1] += pas16->pit.l[1];
|
||||
else
|
||||
pas16->pit.c[1] += 0x10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas16->pit.c[1] = -1;
|
||||
pas16->pit.enable[1] = 0;
|
||||
}
|
||||
|
||||
pas16->irq_stat |= PAS16_INT_PCM;
|
||||
if (pas16->irq_ena & PAS16_INT_PCM)
|
||||
{
|
||||
pclog("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq);
|
||||
picint(1 << pas16->irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pas16_out_base(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
|
||||
io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
|
||||
pas16->base = val << 2;
|
||||
pclog("pas16_write_base : PAS16 base now at %04X\n", pas16->base);
|
||||
|
||||
io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16);
|
||||
}
|
||||
|
||||
|
||||
void pas16_poll(void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
|
||||
if (pas16->pos >= SOUNDBUFLEN)
|
||||
return;
|
||||
|
||||
opl3_poll(&pas16->opl, &pas16->opl_buffer[pas16->pos * 2], &pas16->opl_buffer[(pas16->pos * 2) + 1]);
|
||||
sb_dsp_poll(&pas16->dsp, &pas16->dsp_buffer[pas16->pos * 2], &pas16->dsp_buffer[(pas16->pos * 2) + 1]);
|
||||
|
||||
if (!(pas16->audiofilt & PAS16_FILT_MUTE))
|
||||
{
|
||||
pas16->pcm_buffer[0][pas16->pos] = 0;
|
||||
pas16->pcm_buffer[1][pas16->pos] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l;
|
||||
pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r;
|
||||
}
|
||||
pas16->pos++;
|
||||
}
|
||||
|
||||
void pas16_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
{
|
||||
buffer[c] += pas16->opl_buffer[c];
|
||||
buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp_buffer[c]) / 1.3) / 2;
|
||||
buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2);
|
||||
}
|
||||
|
||||
pas16->pos = 0;
|
||||
}
|
||||
|
||||
void *pas16_init()
|
||||
{
|
||||
pas16_t *pas16 = malloc(sizeof(pas16_t));
|
||||
memset(pas16, 0, sizeof(pas16_t));
|
||||
|
||||
opl3_init(&pas16->opl);
|
||||
sb_dsp_init(&pas16->dsp, SB2);
|
||||
|
||||
io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16);
|
||||
|
||||
timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16);
|
||||
|
||||
sound_add_handler(pas16_poll, pas16_get_buffer, pas16);
|
||||
|
||||
return pas16;
|
||||
}
|
||||
|
||||
void pas16_close(void *p)
|
||||
{
|
||||
pas16_t *pas16 = (pas16_t *)p;
|
||||
|
||||
free(pas16);
|
||||
}
|
||||
|
||||
device_t pas16_device =
|
||||
{
|
||||
"Pro Audio Spectrum 16",
|
||||
pas16_init,
|
||||
pas16_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_pas16.h
Normal file
1
src/sound_pas16.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t pas16_device;
|
||||
412
src/sound_sb.c
Normal file
412
src/sound_sb.c
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
#include "sound_sb.h"
|
||||
#include "sound_sb_dsp.h"
|
||||
#include "sound_opl.h"
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
typedef struct sb_mixer_t
|
||||
{
|
||||
int master_l, master_r;
|
||||
int voice_l, voice_r;
|
||||
int fm_l, fm_r;
|
||||
int bass_l, bass_r;
|
||||
int treble_l, treble_r;
|
||||
int filter;
|
||||
|
||||
int index;
|
||||
uint8_t regs[256];
|
||||
} sb_mixer_t;
|
||||
|
||||
typedef struct sb_t
|
||||
{
|
||||
opl_t opl;
|
||||
sb_dsp_t dsp;
|
||||
sb_mixer_t mixer;
|
||||
|
||||
int16_t opl_buffer[SOUNDBUFLEN * 2];
|
||||
int16_t dsp_buffer[SOUNDBUFLEN * 2];
|
||||
|
||||
int pos;
|
||||
} sb_t;
|
||||
|
||||
static int sb_att[]=
|
||||
{
|
||||
310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479,
|
||||
4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845,
|
||||
39036,46395,55140,65535
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void sb_opl2_poll(void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
|
||||
if (sb->pos >= SOUNDBUFLEN) return;
|
||||
|
||||
opl2_poll(&sb->opl, &sb->opl_buffer[sb->pos * 2], &sb->opl_buffer[(sb->pos * 2) + 1]);
|
||||
sb_dsp_poll(&sb->dsp, &sb->dsp_buffer[sb->pos * 2], &sb->dsp_buffer[(sb->pos * 2) + 1]);
|
||||
sb->pos++;
|
||||
}
|
||||
|
||||
static void sb_opl3_poll(void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
|
||||
if (sb->pos >= SOUNDBUFLEN) return;
|
||||
|
||||
opl3_poll(&sb->opl, &sb->opl_buffer[sb->pos * 2], &sb->opl_buffer[(sb->pos * 2) + 1]);
|
||||
sb_dsp_poll(&sb->dsp, &sb->dsp_buffer[sb->pos * 2], &sb->dsp_buffer[(sb->pos * 2) + 1]);
|
||||
sb->pos++;
|
||||
}
|
||||
|
||||
static void sb_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
sb_mixer_t *mixer = &sb->mixer;
|
||||
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c += 2)
|
||||
{
|
||||
int16_t out_l, out_r;
|
||||
|
||||
out_l = ((sb->opl_buffer[c] * mixer->fm_l) >> 16);
|
||||
out_r = ((sb->opl_buffer[c + 1] * mixer->fm_r) >> 16);
|
||||
if (sb->mixer.filter)
|
||||
{
|
||||
out_l += (int)(((sb_iir(0, (float)sb->dsp_buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16;
|
||||
out_r += (int)(((sb_iir(1, (float)sb->dsp_buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_l += ((sb->dsp_buffer[c] * mixer->voice_l) / 3) >> 16;
|
||||
out_r += ((sb->dsp_buffer[c + 1] * mixer->voice_r) / 3) >> 16;
|
||||
}
|
||||
|
||||
out_l = (out_l * mixer->master_l) >> 16;
|
||||
out_r = (out_r * mixer->master_r) >> 16;
|
||||
|
||||
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
|
||||
{
|
||||
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
|
||||
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
|
||||
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
|
||||
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
|
||||
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
|
||||
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
|
||||
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
|
||||
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
|
||||
}
|
||||
|
||||
buffer[c] += out_l;
|
||||
buffer[c + 1] += out_r;
|
||||
}
|
||||
|
||||
sb->pos = 0;
|
||||
}
|
||||
|
||||
|
||||
void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
sb_mixer_t *mixer = &sb->mixer;
|
||||
|
||||
if (!(addr & 1))
|
||||
mixer->index = val & 0xff;
|
||||
else
|
||||
{
|
||||
mixer->regs[mixer->index] = val;
|
||||
|
||||
mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11];
|
||||
mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11];
|
||||
mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11];
|
||||
mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11];
|
||||
mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11];
|
||||
mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11];
|
||||
mixer->filter = !(mixer->regs[0xe] & 0x20);
|
||||
mixer->bass_l = mixer->bass_r = 8;
|
||||
mixer->treble_l = mixer->treble_r = 8;
|
||||
pclog("%02X %02X %02X\n", mixer->regs[0x04], mixer->regs[0x22], mixer->regs[0x26]);
|
||||
pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r);
|
||||
if (mixer->index == 0xe)
|
||||
sb_dsp_set_stereo(&sb->dsp, val & 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sb_pro_mixer_read(uint16_t addr, void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
sb_mixer_t *mixer = &sb->mixer;
|
||||
|
||||
if (!(addr & 1))
|
||||
return mixer->index;
|
||||
|
||||
return mixer->regs[mixer->index];
|
||||
}
|
||||
|
||||
void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
sb_mixer_t *mixer = &sb->mixer;
|
||||
|
||||
if (!(addr & 1))
|
||||
mixer->index = val;
|
||||
else
|
||||
{
|
||||
mixer->regs[mixer->index] = val;
|
||||
switch (mixer->index)
|
||||
{
|
||||
case 0x22:
|
||||
mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3;
|
||||
mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3;
|
||||
break;
|
||||
case 0x04:
|
||||
mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3;
|
||||
mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3;
|
||||
break;
|
||||
case 0x26:
|
||||
mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3;
|
||||
mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3;
|
||||
break;
|
||||
case 0x80:
|
||||
if (val & 1) sb->dsp.sb_irqnum = 2;
|
||||
if (val & 2) sb->dsp.sb_irqnum = 5;
|
||||
if (val & 4) sb->dsp.sb_irqnum = 7;
|
||||
if (val & 8) sb->dsp.sb_irqnum = 10;
|
||||
break;
|
||||
}
|
||||
mixer->master_l = sb_att[mixer->regs[0x30] >> 3];
|
||||
mixer->master_r = sb_att[mixer->regs[0x31] >> 3];
|
||||
mixer->voice_l = sb_att[mixer->regs[0x32] >> 3];
|
||||
mixer->voice_r = sb_att[mixer->regs[0x33] >> 3];
|
||||
mixer->fm_l = sb_att[mixer->regs[0x34] >> 3];
|
||||
mixer->fm_r = sb_att[mixer->regs[0x35] >> 3];
|
||||
mixer->bass_l = mixer->regs[0x46] >> 4;
|
||||
mixer->bass_r = mixer->regs[0x47] >> 4;
|
||||
mixer->treble_l = mixer->regs[0x44] >> 4;
|
||||
mixer->treble_r = mixer->regs[0x45] >> 4;
|
||||
mixer->filter = 0;
|
||||
pclog("%02X %02X %02X %02X %02X %02X\n", mixer->regs[0x30], mixer->regs[0x31], mixer->regs[0x32], mixer->regs[0x33], mixer->regs[0x34], mixer->regs[0x35]);
|
||||
pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sb_16_mixer_read(uint16_t addr, void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
sb_mixer_t *mixer = &sb->mixer;
|
||||
|
||||
if (!(addr & 1))
|
||||
return mixer->index;
|
||||
|
||||
switch (mixer->index)
|
||||
{
|
||||
case 0x80:
|
||||
switch (sb->dsp.sb_irqnum)
|
||||
{
|
||||
case 2: return 1; /*IRQ 7*/
|
||||
case 5: return 2; /*IRQ 7*/
|
||||
case 7: return 4; /*IRQ 7*/
|
||||
case 10: return 8; /*IRQ 7*/
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
return 0x22; /*DMA 1 and 5*/
|
||||
case 0x82:
|
||||
return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0);
|
||||
}
|
||||
return mixer->regs[mixer->index];
|
||||
}
|
||||
|
||||
void sb_mixer_init(sb_mixer_t *mixer)
|
||||
{
|
||||
mixer->master_l = mixer->master_r = 65535;
|
||||
mixer->voice_l = mixer->voice_r = 65535;
|
||||
mixer->fm_l = mixer->fm_r = 65535;
|
||||
mixer->bass_l = mixer->bass_r = 8;
|
||||
mixer->treble_l = mixer->treble_r = 8;
|
||||
mixer->filter = 1;
|
||||
}
|
||||
|
||||
void *sb_1_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl2_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SB1);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
sound_add_handler(sb_opl2_poll, sb_get_buffer, sb);
|
||||
return sb;
|
||||
}
|
||||
void *sb_15_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl2_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SB15);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
sound_add_handler(sb_opl2_poll, sb_get_buffer, sb);
|
||||
return sb;
|
||||
}
|
||||
void *sb_2_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl2_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SB2);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
sound_add_handler(sb_opl2_poll, sb_get_buffer, sb);
|
||||
return sb;
|
||||
}
|
||||
|
||||
void *sb_pro_v1_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl2_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SBPRO);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0220, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0222, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0228, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0224, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
|
||||
sound_add_handler(sb_opl2_poll, sb_get_buffer, sb);
|
||||
|
||||
sb->mixer.regs[0x22] = 0xff;
|
||||
sb->mixer.regs[0x04] = 0xff;
|
||||
sb->mixer.regs[0x26] = 0xff;
|
||||
sb->mixer.regs[0xe] = 0;
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
void *sb_pro_v2_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl3_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SBPRO2);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0224, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
|
||||
sound_add_handler(sb_opl3_poll, sb_get_buffer, sb);
|
||||
|
||||
sb->mixer.regs[0x22] = 0xff;
|
||||
sb->mixer.regs[0x04] = 0xff;
|
||||
sb->mixer.regs[0x26] = 0xff;
|
||||
sb->mixer.regs[0xe] = 0;
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
void *sb_16_init()
|
||||
{
|
||||
sb_t *sb = malloc(sizeof(sb_t));
|
||||
memset(sb, 0, sizeof(sb_t));
|
||||
|
||||
opl3_init(&sb->opl);
|
||||
sb_dsp_init(&sb->dsp, SB16);
|
||||
sb_dsp_setaddr(&sb->dsp, 0x0220);
|
||||
sb_mixer_init(&sb->mixer);
|
||||
io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
|
||||
io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb);
|
||||
sound_add_handler(sb_opl3_poll, sb_get_buffer, sb);
|
||||
|
||||
sb->mixer.regs[0x30] = 31 << 3;
|
||||
sb->mixer.regs[0x31] = 31 << 3;
|
||||
sb->mixer.regs[0x32] = 31 << 3;
|
||||
sb->mixer.regs[0x33] = 31 << 3;
|
||||
sb->mixer.regs[0x34] = 31 << 3;
|
||||
sb->mixer.regs[0x35] = 31 << 3;
|
||||
sb->mixer.regs[0x44] = 8 << 4;
|
||||
sb->mixer.regs[0x45] = 8 << 4;
|
||||
sb->mixer.regs[0x46] = 8 << 4;
|
||||
sb->mixer.regs[0x47] = 8 << 4;
|
||||
sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4);
|
||||
sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4);
|
||||
sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4);
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
void sb_close(void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
|
||||
free(sb);
|
||||
}
|
||||
|
||||
void sb_speed_changed(void *p)
|
||||
{
|
||||
sb_t *sb = (sb_t *)p;
|
||||
|
||||
sb_dsp_speed_changed(&sb->dsp);
|
||||
}
|
||||
|
||||
device_t sb_1_device =
|
||||
{
|
||||
"Sound Blaster v1.0",
|
||||
sb_1_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
device_t sb_15_device =
|
||||
{
|
||||
"Sound Blaster v1.5",
|
||||
sb_15_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
device_t sb_2_device =
|
||||
{
|
||||
"Sound Blaster v2.0",
|
||||
sb_2_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
device_t sb_pro_v1_device =
|
||||
{
|
||||
"Sound Blaster Pro v1",
|
||||
sb_pro_v1_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
device_t sb_pro_v2_device =
|
||||
{
|
||||
"Sound Blaster Pro v2",
|
||||
sb_pro_v2_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
device_t sb_16_device =
|
||||
{
|
||||
"Sound Blaster 16",
|
||||
sb_16_init,
|
||||
sb_close,
|
||||
sb_speed_changed
|
||||
};
|
||||
6
src/sound_sb.h
Normal file
6
src/sound_sb.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extern device_t sb_1_device;
|
||||
extern device_t sb_15_device;
|
||||
extern device_t sb_2_device;
|
||||
extern device_t sb_pro_v1_device;
|
||||
extern device_t sb_pro_v2_device;
|
||||
extern device_t sb_16_device;
|
||||
908
src/sound_sb_dsp.c
Normal file
908
src/sound_sb_dsp.c
Normal file
|
|
@ -0,0 +1,908 @@
|
|||
/*Jazz sample rates :
|
||||
386-33 - 12kHz
|
||||
486-33 - 20kHz
|
||||
486-50 - 32kHz
|
||||
Pentium - 45kHz*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "ibm.h"
|
||||
|
||||
|
||||
#include "dma.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "sound.h"
|
||||
#include "sound_sb_dsp.h"
|
||||
#include "timer.h"
|
||||
|
||||
void pollsb(void *p);
|
||||
void sb_poll_i(void *p);
|
||||
|
||||
|
||||
|
||||
static int sbe2dat[4][9] = {
|
||||
{ 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 },
|
||||
{ -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 },
|
||||
{ -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 },
|
||||
{ 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 }
|
||||
};
|
||||
|
||||
static int sb_commands[256]=
|
||||
{
|
||||
-1,-1,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1,
|
||||
1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0,
|
||||
0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
1, 2, 2,-1,-1,-1,-1,-1, 2,-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,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0,
|
||||
2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1,
|
||||
0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1,
|
||||
1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0
|
||||
};
|
||||
|
||||
char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
|
||||
uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405};
|
||||
|
||||
/*These tables were 'borrowed' from DOSBox*/
|
||||
int8_t scaleMap4[64] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15,
|
||||
2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30,
|
||||
4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60
|
||||
};
|
||||
uint8_t adjustMap4[64] = {
|
||||
0, 0, 0, 0, 0, 16, 16, 16,
|
||||
0, 0, 0, 0, 0, 16, 16, 16,
|
||||
240, 0, 0, 0, 0, 16, 16, 16,
|
||||
240, 0, 0, 0, 0, 16, 16, 16,
|
||||
240, 0, 0, 0, 0, 16, 16, 16,
|
||||
240, 0, 0, 0, 0, 16, 16, 16,
|
||||
240, 0, 0, 0, 0, 0, 0, 0,
|
||||
240, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
int8_t scaleMap26[40] = {
|
||||
0, 1, 2, 3, 0, -1, -2, -3,
|
||||
1, 3, 5, 7, -1, -3, -5, -7,
|
||||
2, 6, 10, 14, -2, -6, -10, -14,
|
||||
4, 12, 20, 28, -4, -12, -20, -28,
|
||||
5, 15, 25, 35, -5, -15, -25, -35
|
||||
};
|
||||
uint8_t adjustMap26[40] = {
|
||||
0, 0, 0, 8, 0, 0, 0, 8,
|
||||
248, 0, 0, 8, 248, 0, 0, 8,
|
||||
248, 0, 0, 8, 248, 0, 0, 8,
|
||||
248, 0, 0, 8, 248, 0, 0, 8,
|
||||
248, 0, 0, 0, 248, 0, 0, 0
|
||||
};
|
||||
|
||||
int8_t scaleMap2[24] = {
|
||||
0, 1, 0, -1, 1, 3, -1, -3,
|
||||
2, 6, -2, -6, 4, 12, -4, -12,
|
||||
8, 24, -8, -24, 6, 48, -16, -48
|
||||
};
|
||||
uint8_t adjustMap2[24] = {
|
||||
0, 4, 0, 4,
|
||||
252, 4, 252, 4, 252, 4, 252, 4,
|
||||
252, 4, 252, 4, 252, 4, 252, 4,
|
||||
252, 0, 252, 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
void sb_irq(sb_dsp_t *dsp, int irq8)
|
||||
{
|
||||
// pclog("IRQ %i %02X\n",irq8,pic.mask);
|
||||
if (irq8) dsp->sb_irq8 = 1;
|
||||
else dsp->sb_irq16 = 1;
|
||||
picint(1 << dsp->sb_irqnum);
|
||||
}
|
||||
void sb_irqc(sb_dsp_t *dsp, int irq8)
|
||||
{
|
||||
if (irq8) dsp->sb_irq8 = 0;
|
||||
else dsp->sb_irq16 = 0;
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
}
|
||||
|
||||
void sb_dsp_reset(sb_dsp_t *dsp)
|
||||
{
|
||||
dsp->sbenable = dsp->sb_enable_i = 0;
|
||||
dsp->sb_command = 0;
|
||||
|
||||
dsp->sb_8_length = 0xffff;
|
||||
|
||||
sb_irqc(dsp, 0);
|
||||
sb_irqc(dsp, 1);
|
||||
dsp->sb_16_pause = 0;
|
||||
dsp->sb_read_wp = dsp->sb_read_rp = 0;
|
||||
dsp->sb_data_stat = -1;
|
||||
dsp->sb_speaker = 0;
|
||||
dsp->sb_pausetime = -1;
|
||||
dsp->sbe2 = 0xAA;
|
||||
dsp->sbe2count = 0;
|
||||
|
||||
dsp->sbreset = 0;
|
||||
dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0;
|
||||
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
}
|
||||
|
||||
void sb_doreset(sb_dsp_t *dsp)
|
||||
{
|
||||
int c;
|
||||
|
||||
sb_dsp_reset(dsp);
|
||||
|
||||
if (dsp->sb_type==SB16) sb_commands[8] = 1;
|
||||
else sb_commands[8] = -1;
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
dsp->sb_asp_regs[c] = 0;
|
||||
dsp->sb_asp_regs[5] = 0x01;
|
||||
dsp->sb_asp_regs[9] = 0xf8;
|
||||
}
|
||||
|
||||
void sb_dsp_speed_changed(sb_dsp_t *dsp)
|
||||
{
|
||||
if (dsp->sb_timeo < 256)
|
||||
dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo);
|
||||
else
|
||||
dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256)));
|
||||
|
||||
if (dsp->sb_timei < 256)
|
||||
dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei);
|
||||
else
|
||||
dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256)));
|
||||
}
|
||||
|
||||
void sb_add_data(sb_dsp_t *dsp, uint8_t v)
|
||||
{
|
||||
dsp->sb_read_data[dsp->sb_read_wp++] = v;
|
||||
dsp->sb_read_wp &= 0xff;
|
||||
}
|
||||
|
||||
#define ADPCM_4 1
|
||||
#define ADPCM_26 2
|
||||
#define ADPCM_2 3
|
||||
|
||||
void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
{
|
||||
if (dma8)
|
||||
{
|
||||
dsp->sb_8_length = len;
|
||||
dsp->sb_8_format = format;
|
||||
dsp->sb_8_autoinit = autoinit;
|
||||
dsp->sb_8_pause = 0;
|
||||
dsp->sb_8_enable = 1;
|
||||
if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0;
|
||||
dsp->sb_8_output = 1;
|
||||
timer_process();
|
||||
dsp->sbenable = dsp->sb_8_enable;
|
||||
timer_update_outstanding();
|
||||
dsp->sbleftright = 0;
|
||||
dsp->sbdacpos = 0;
|
||||
// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
|
||||
}
|
||||
else
|
||||
{
|
||||
dsp->sb_16_length = len;
|
||||
dsp->sb_16_format = format;
|
||||
dsp->sb_16_autoinit = autoinit;
|
||||
dsp->sb_16_pause = 0;
|
||||
dsp->sb_16_enable = 1;
|
||||
if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0;
|
||||
dsp->sb_16_output = 1;
|
||||
timer_process();
|
||||
dsp->sbenable = dsp->sb_16_enable;
|
||||
timer_update_outstanding();
|
||||
// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len);
|
||||
}
|
||||
}
|
||||
|
||||
void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
{
|
||||
if (dma8)
|
||||
{
|
||||
dsp->sb_8_length = len;
|
||||
dsp->sb_8_format = format;
|
||||
dsp->sb_8_autoinit = autoinit;
|
||||
dsp->sb_8_pause = 0;
|
||||
dsp->sb_8_enable = 1;
|
||||
if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0;
|
||||
dsp->sb_8_output = 0;
|
||||
timer_process();
|
||||
dsp->sb_enable_i = dsp->sb_8_enable;
|
||||
timer_update_outstanding();
|
||||
// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
|
||||
}
|
||||
else
|
||||
{
|
||||
dsp->sb_16_length = len;
|
||||
dsp->sb_16_format = format;
|
||||
dsp->sb_16_autoinit = autoinit;
|
||||
dsp->sb_16_pause = 0;
|
||||
dsp->sb_16_enable = 1;
|
||||
if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0;
|
||||
dsp->sb_16_output = 0;
|
||||
timer_process();
|
||||
dsp->sb_enable_i = dsp->sb_16_enable;
|
||||
timer_update_outstanding();
|
||||
// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
|
||||
}
|
||||
}
|
||||
|
||||
int sb_8_read_dma(sb_dsp_t *dsp)
|
||||
{
|
||||
return dma_channel_read(dsp->sb_8_dmanum);
|
||||
}
|
||||
void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val)
|
||||
{
|
||||
dma_channel_write(dsp->sb_8_dmanum, val);
|
||||
}
|
||||
uint16_t sb_16_read_dma(sb_dsp_t *dsp)
|
||||
{
|
||||
return dma_channel_read(5);
|
||||
}
|
||||
void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val)
|
||||
{
|
||||
dma_channel_write(5, val);
|
||||
}
|
||||
|
||||
void sb_dsp_setirq(sb_dsp_t *dsp, int irq)
|
||||
{
|
||||
dsp->sb_irqnum = irq;
|
||||
}
|
||||
|
||||
void sb_dsp_setdma8(sb_dsp_t *dsp, int dma)
|
||||
{
|
||||
dsp->sb_8_dmanum = dma;
|
||||
}
|
||||
|
||||
void sb_exec_command(sb_dsp_t *dsp)
|
||||
{
|
||||
int temp,c;
|
||||
pclog("sb_exec_command : SB command %02X\n", dsp->sb_command);
|
||||
switch (dsp->sb_command)
|
||||
{
|
||||
case 0x10: /*8-bit direct mode*/
|
||||
dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8;
|
||||
break;
|
||||
case 0x14: /*8-bit single cycle DMA output*/
|
||||
sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
break;
|
||||
case 0x17: /*2-bit ADPCM output with reference*/
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbstep = 0;
|
||||
// pclog("Ref byte 2 %02X\n",sbref);
|
||||
case 0x16: /*2-bit ADPCM output*/
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x1C: /*8-bit autoinit DMA output*/
|
||||
if (dsp->sb_type < SB15) break;
|
||||
sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen);
|
||||
break;
|
||||
case 0x1F: /*2-bit ADPCM autoinit output*/
|
||||
if (dsp->sb_type < SB15) break;
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x20: /*8-bit direct input*/
|
||||
sb_add_data(dsp, 0);
|
||||
break;
|
||||
case 0x24: /*8-bit single cycle DMA input*/
|
||||
sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
break;
|
||||
case 0x2C: /*8-bit autoinit DMA input*/
|
||||
if (dsp->sb_type < SB15) break;
|
||||
sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
break;
|
||||
case 0x40: /*Set time constant*/
|
||||
dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0];
|
||||
dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]);
|
||||
temp = 256 - dsp->sb_data[0];
|
||||
temp = 1000000 / temp;
|
||||
// printf("Sample rate - %ihz (%i)\n",temp, sblatcho);
|
||||
dsp->sb_freq = temp;
|
||||
break;
|
||||
case 0x41: /*Set output sampling rate*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8))));
|
||||
// printf("Sample rate - %ihz (%i)\n",sb_data[1]+(sb_data[0]<<8), sblatcho);
|
||||
dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8);
|
||||
dsp->sb_timeo = 256 + dsp->sb_freq;
|
||||
break;
|
||||
case 0x42: /*Set input sampling rate*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8))));
|
||||
// printf("iample rate - %ihz\n",sb_data[1]+(sb_data[0]<<8));
|
||||
dsp->sb_timei = 256 + dsp->sb_data[1] + (dsp->sb_data[0] << 8);
|
||||
break;
|
||||
case 0x48: /*Set DSP block transfer size*/
|
||||
dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
|
||||
break;
|
||||
case 0x75: /*4-bit ADPCM output with reference*/
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbstep = 0;
|
||||
// pclog("Ref byte 4 %02X\n",sbref);
|
||||
case 0x74: /*4-bit ADPCM output*/
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x77: /*2.6-bit ADPCM output with reference*/
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbstep = 0;
|
||||
// pclog("Ref byte 26 %02X\n",sbref);
|
||||
case 0x76: /*2.6-bit ADPCM output*/
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x7D: /*4-bit ADPCM autoinit output*/
|
||||
if (dsp->sb_type < SB15) break;
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x7F: /*2.6-bit ADPCM autoinit output*/
|
||||
if (dsp->sb_type < SB15) break;
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x80: /*Pause DAC*/
|
||||
dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
|
||||
// pclog("SB pause %04X\n",sb_pausetime);
|
||||
timer_process();
|
||||
dsp->sbenable = 1;
|
||||
timer_update_outstanding();
|
||||
break;
|
||||
case 0x90: /*High speed 8-bit autoinit DMA output*/
|
||||
if (dsp->sb_type < SB2) break;
|
||||
sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen);
|
||||
break;
|
||||
case 0x91: /*High speed 8-bit single cycle DMA output*/
|
||||
if (dsp->sb_type < SB2) break;
|
||||
sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen);
|
||||
break;
|
||||
case 0x98: /*High speed 8-bit autoinit DMA input*/
|
||||
if (dsp->sb_type < SB2) break;
|
||||
sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen);
|
||||
break;
|
||||
case 0x99: /*High speed 8-bit single cycle DMA input*/
|
||||
if (dsp->sb_type < SB2) break;
|
||||
sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen);
|
||||
break;
|
||||
case 0xA0: /*Set input mode to mono*/
|
||||
case 0xA8: /*Set input mode to stereo*/
|
||||
break;
|
||||
case 0xB0: case 0xB1: case 0xB2: case 0xB3:
|
||||
case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
|
||||
dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
|
||||
break;
|
||||
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
|
||||
case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
|
||||
dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
|
||||
break;
|
||||
case 0xC0: case 0xC1: case 0xC2: case 0xC3:
|
||||
case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
|
||||
dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
|
||||
break;
|
||||
case 0xC8: case 0xC9: case 0xCA: case 0xCB:
|
||||
case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
|
||||
dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
|
||||
break;
|
||||
case 0xD0: /*Pause 8-bit DMA*/
|
||||
dsp->sb_8_pause = 1;
|
||||
break;
|
||||
case 0xD1: /*Speaker on*/
|
||||
dsp->sb_speaker = 1;
|
||||
break;
|
||||
case 0xD3: /*Speaker off*/
|
||||
dsp->sb_speaker = 0;
|
||||
break;
|
||||
case 0xD4: /*Continue 8-bit DMA*/
|
||||
dsp->sb_8_pause = 0;
|
||||
break;
|
||||
case 0xD5: /*Pause 16-bit DMA*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sb_16_pause = 1;
|
||||
break;
|
||||
case 0xD6: /*Continue 16-bit DMA*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sb_16_pause = 0;
|
||||
break;
|
||||
case 0xD8: /*Get speaker status*/
|
||||
sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0);
|
||||
break;
|
||||
case 0xD9: /*Exit 16-bit auto-init mode*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sb_16_autoinit = 0;
|
||||
break;
|
||||
case 0xDA: /*Exit 8-bit auto-init mode*/
|
||||
dsp->sb_8_autoinit = 0;
|
||||
break;
|
||||
case 0xE0: /*DSP identification*/
|
||||
sb_add_data(dsp, ~dsp->sb_data[0]);
|
||||
break;
|
||||
case 0xE1: /*Get DSP version*/
|
||||
sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8);
|
||||
sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff);
|
||||
break;
|
||||
case 0xE2: /*Stupid ID/protection*/
|
||||
for (c = 0; c < 8; c++)
|
||||
if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c];
|
||||
dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8];
|
||||
dsp->sbe2count++;
|
||||
sb_8_write_dma(dsp, dsp->sbe2);
|
||||
break;
|
||||
case 0xE3: /*DSP copyright*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
c = 0;
|
||||
while (sb16_copyright[c])
|
||||
sb_add_data(dsp, sb16_copyright[c++]);
|
||||
sb_add_data(dsp, 0);
|
||||
break;
|
||||
case 0xE4: /*Write test register*/
|
||||
dsp->sb_test = dsp->sb_data[0];
|
||||
break;
|
||||
case 0xE8: /*Read test register*/
|
||||
sb_add_data(dsp, dsp->sb_test);
|
||||
break;
|
||||
case 0xF2: /*Trigger 8-bit IRQ*/
|
||||
// pclog("Trigger IRQ\n");
|
||||
sb_irq(dsp, 1);
|
||||
break;
|
||||
case 0xE7: /*???*/
|
||||
case 0xFA: /*???*/
|
||||
break;
|
||||
case 0x07: /*No, that's not how you program auto-init DMA*/
|
||||
case 0xFF:
|
||||
break;
|
||||
case 0x08: /*ASP get version*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
sb_add_data(dsp, 0x18);
|
||||
break;
|
||||
case 0x0E: /*ASP set register*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1];
|
||||
// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]);
|
||||
break;
|
||||
case 0x0F: /*ASP get register*/
|
||||
if (dsp->sb_type < SB16) break;
|
||||
// sb_add_data(0);
|
||||
sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]);
|
||||
// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]);
|
||||
break;
|
||||
case 0xF9:
|
||||
if (dsp->sb_type < SB16) break;
|
||||
if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff);
|
||||
else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07);
|
||||
else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38);
|
||||
else sb_add_data(dsp, 0x00);
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
break;
|
||||
// default:
|
||||
// fatal("Exec bad SB command %02X\n",sb_command);
|
||||
}
|
||||
}
|
||||
|
||||
void sb_write(uint16_t a, uint8_t v, void *priv)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *)priv;
|
||||
printf("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command);
|
||||
switch (a&0xF)
|
||||
{
|
||||
case 6: /*Reset*/
|
||||
if (!(v & 1) && (dsp->sbreset & 1))
|
||||
{
|
||||
sb_dsp_reset(dsp);
|
||||
sb_add_data(dsp, 0xAA);
|
||||
}
|
||||
dsp->sbreset = v;
|
||||
return;
|
||||
case 0xC: /*Command/data write*/
|
||||
if (dsp->sb_data_stat == -1)
|
||||
{
|
||||
dsp->sb_command = v;
|
||||
// if (sb_commands[v]==-1)
|
||||
// fatal("Bad SB command %02X\n",v);
|
||||
dsp->sb_data_stat++;
|
||||
}
|
||||
else
|
||||
dsp->sb_data[dsp->sb_data_stat++] = v;
|
||||
if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1)
|
||||
{
|
||||
sb_exec_command(dsp);
|
||||
dsp->sb_data_stat = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sb_read(uint16_t a, void *priv)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *)priv;
|
||||
// if (a==0x224) output=1;
|
||||
pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc);
|
||||
switch (a & 0xf)
|
||||
{
|
||||
case 0xA: /*Read data*/
|
||||
dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp];
|
||||
if (dsp->sb_read_rp != dsp->sb_read_wp)
|
||||
{
|
||||
dsp->sb_read_rp++;
|
||||
dsp->sb_read_rp &= 0xFF;
|
||||
}
|
||||
// pclog("SB read %02X\n",sbreaddat);
|
||||
return dsp->sbreaddat;
|
||||
case 0xC: /*Write data ready*/
|
||||
cycles -= 100;
|
||||
dsp->writebusy++;
|
||||
if (dsp->writebusy & 8) return 0xff;
|
||||
return 0x7f;
|
||||
case 0xE: /*Read data ready*/
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->sb_irq8 = dsp->sb_irq16 = 0;
|
||||
return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff;
|
||||
case 0xF: /*16-bit ack*/
|
||||
dsp->sb_irq16 = 0;
|
||||
if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum);
|
||||
return 0xff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sb_dsp_init(sb_dsp_t *dsp, int type)
|
||||
{
|
||||
dsp->sb_type = type;
|
||||
|
||||
dsp->sb_irqnum = 7;
|
||||
dsp->sb_8_dmanum = 1;
|
||||
|
||||
sb_doreset(dsp);
|
||||
|
||||
timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp);
|
||||
timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp);
|
||||
}
|
||||
|
||||
void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr)
|
||||
{
|
||||
pclog("sb_dsp_setaddr : %04X\n", addr);
|
||||
io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
|
||||
io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
|
||||
dsp->sb_addr = addr;
|
||||
if (dsp->sb_addr != 0)
|
||||
{
|
||||
io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
|
||||
io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
|
||||
}
|
||||
}
|
||||
|
||||
void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo)
|
||||
{
|
||||
dsp->stereo = stereo;
|
||||
}
|
||||
|
||||
void pollsb(void *p)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *)p;
|
||||
int tempi,ref;
|
||||
|
||||
dsp->sbcount += dsp->sblatcho;
|
||||
// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);
|
||||
if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output)
|
||||
{
|
||||
int data[2];
|
||||
// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho);
|
||||
switch (dsp->sb_8_format)
|
||||
{
|
||||
case 0x00: /*Mono unsigned*/
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
/*Needed to prevent clicking in Worms, which programs the DSP to
|
||||
auto-init DMA but programs the DMA controller to single cycle*/
|
||||
if (data[0] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdat = (data[0] ^ 0x80) << 8;
|
||||
if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
|
||||
{
|
||||
if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
|
||||
else dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sbleftright = !dsp->sbleftright;
|
||||
}
|
||||
else
|
||||
dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x10: /*Mono signed*/
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
if (data[0] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdat = data[0] << 8;
|
||||
if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
|
||||
{
|
||||
if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
|
||||
else dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sbleftright = !dsp->sbleftright;
|
||||
}
|
||||
else
|
||||
dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x20: /*Stereo unsigned*/
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[1] = sb_8_read_dma(dsp);
|
||||
if (data[0] == DMA_NODATA || data[1] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdatl = (data[0] ^ 0x80) << 8;
|
||||
dsp->sbdatr = (data[1] ^ 0x80) << 8;
|
||||
dsp->sb_8_length -= 2;
|
||||
break;
|
||||
case 0x30: /*Stereo signed*/
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[1] = sb_8_read_dma(dsp);
|
||||
if (data[0] == DMA_NODATA || data[1] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdatl = data[0] << 8;
|
||||
dsp->sbdatr = data[1] << 8;
|
||||
dsp->sb_8_length -= 2;
|
||||
break;
|
||||
|
||||
case ADPCM_4:
|
||||
if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep;
|
||||
else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep;
|
||||
if (tempi < 0) tempi = 0;
|
||||
if (tempi > 63) tempi = 63;
|
||||
|
||||
ref = dsp->sbref + scaleMap4[tempi];
|
||||
if (ref > 0xff) dsp->sbref = 0xff;
|
||||
else if (ref < 0x00) dsp->sbref = 0x00;
|
||||
else dsp->sbref = ref;
|
||||
|
||||
dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff;
|
||||
|
||||
dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
|
||||
|
||||
dsp->sbdacpos++;
|
||||
if (dsp->sbdacpos >= 2)
|
||||
{
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
|
||||
if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
|
||||
{
|
||||
if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
|
||||
else dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sbleftright = !dsp->sbleftright;
|
||||
}
|
||||
else
|
||||
dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
|
||||
break;
|
||||
|
||||
case ADPCM_26:
|
||||
if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep;
|
||||
else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep;
|
||||
else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep;
|
||||
|
||||
if (tempi < 0) tempi = 0;
|
||||
if (tempi > 39) tempi = 39;
|
||||
|
||||
ref = dsp->sbref + scaleMap26[tempi];
|
||||
if (ref > 0xff) dsp->sbref = 0xff;
|
||||
else if (ref < 0x00) dsp->sbref = 0x00;
|
||||
else dsp->sbref = ref;
|
||||
dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff;
|
||||
|
||||
dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
|
||||
|
||||
dsp->sbdacpos++;
|
||||
if (dsp->sbdacpos>=3)
|
||||
{
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
|
||||
if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
|
||||
{
|
||||
if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
|
||||
else dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sbleftright = !dsp->sbleftright;
|
||||
}
|
||||
else
|
||||
dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
|
||||
break;
|
||||
|
||||
case ADPCM_2:
|
||||
tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep;
|
||||
if (tempi < 0) tempi = 0;
|
||||
if (tempi > 23) tempi = 23;
|
||||
|
||||
ref = dsp->sbref + scaleMap2[tempi];
|
||||
if (ref > 0xff) dsp->sbref = 0xff;
|
||||
else if (ref < 0x00) dsp->sbref = 0x00;
|
||||
else dsp->sbref = ref;
|
||||
dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff;
|
||||
|
||||
dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
|
||||
|
||||
dsp->sbdacpos++;
|
||||
if (dsp->sbdacpos >= 4)
|
||||
{
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
}
|
||||
|
||||
if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
|
||||
{
|
||||
if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
|
||||
else dsp->sbdatr = dsp->sbdat;
|
||||
dsp->sbleftright = !dsp->sbleftright;
|
||||
}
|
||||
else
|
||||
dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
|
||||
break;
|
||||
|
||||
// default:
|
||||
//fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format);
|
||||
}
|
||||
|
||||
if (dsp->sb_8_length < 0)
|
||||
{
|
||||
if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
|
||||
else dsp->sb_8_enable = dsp->sbenable=0;
|
||||
sb_irq(dsp, 1);
|
||||
}
|
||||
}
|
||||
if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output)
|
||||
{
|
||||
switch (dsp->sb_16_format)
|
||||
{
|
||||
case 0x00: /*Mono unsigned*/
|
||||
dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000;
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x10: /*Mono signed*/
|
||||
dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp);
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x20: /*Stereo unsigned*/
|
||||
dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000;
|
||||
dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000;
|
||||
dsp->sb_16_length -= 2;
|
||||
break;
|
||||
case 0x30: /*Stereo signed*/
|
||||
dsp->sbdatl = sb_16_read_dma(dsp);
|
||||
dsp->sbdatr = sb_16_read_dma(dsp);
|
||||
dsp->sb_16_length -= 2;
|
||||
break;
|
||||
|
||||
// default:
|
||||
// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format);
|
||||
}
|
||||
|
||||
if (dsp->sb_16_length < 0)
|
||||
{
|
||||
// pclog("16DMA over %i\n",sb_16_autoinit);
|
||||
if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
|
||||
else dsp->sb_16_enable = dsp->sbenable = 0;
|
||||
sb_irq(dsp, 0);
|
||||
}
|
||||
}
|
||||
if (dsp->sb_pausetime > -1)
|
||||
{
|
||||
dsp->sb_pausetime--;
|
||||
if (dsp->sb_pausetime < 0)
|
||||
{
|
||||
sb_irq(dsp, 1);
|
||||
dsp->sbenable = dsp->sb_8_enable;
|
||||
pclog("SB pause over\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sb_poll_i(void *p)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *)p;
|
||||
|
||||
dsp->sb_count_i += dsp->sblatchi;
|
||||
// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);
|
||||
if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output)
|
||||
{
|
||||
switch (dsp->sb_8_format)
|
||||
{
|
||||
case 0x00: /*Mono unsigned*/
|
||||
sb_8_write_dma(dsp, 0x80);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x10: /*Mono signed*/
|
||||
sb_8_write_dma(dsp, 0x00);
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x20: /*Stereo unsigned*/
|
||||
sb_8_write_dma(dsp, 0x80);
|
||||
sb_8_write_dma(dsp, 0x80);
|
||||
dsp->sb_8_length -= 2;
|
||||
break;
|
||||
case 0x30: /*Stereo signed*/
|
||||
sb_8_write_dma(dsp, 0x00);
|
||||
sb_8_write_dma(dsp, 0x00);
|
||||
dsp->sb_8_length -= 2;
|
||||
break;
|
||||
|
||||
// default:
|
||||
// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format);
|
||||
}
|
||||
|
||||
if (dsp->sb_8_length < 0)
|
||||
{
|
||||
// pclog("Input DMA over %i\n",sb_8_autoinit);
|
||||
if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
|
||||
else dsp->sb_8_enable = dsp->sbenable = 0;
|
||||
sb_irq(dsp, 1);
|
||||
}
|
||||
}
|
||||
if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output)
|
||||
{
|
||||
switch (dsp->sb_16_format)
|
||||
{
|
||||
case 0x00: /*Unsigned mono*/
|
||||
sb_16_write_dma(dsp, 0x8000);
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x10: /*Signed mono*/
|
||||
sb_16_write_dma(dsp, 0);
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x20: /*Unsigned stereo*/
|
||||
sb_16_write_dma(dsp, 0x8000);
|
||||
sb_16_write_dma(dsp, 0x8000);
|
||||
dsp->sb_16_length -= 2;
|
||||
break;
|
||||
case 0x30: /*Signed stereo*/
|
||||
sb_16_write_dma(dsp, 0);
|
||||
sb_16_write_dma(dsp, 0);
|
||||
dsp->sb_16_length -= 2;
|
||||
break;
|
||||
|
||||
// default:
|
||||
// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format);
|
||||
}
|
||||
|
||||
if (dsp->sb_16_length < 0)
|
||||
{
|
||||
// pclog("16iDMA over %i\n",sb_16_autoinit);
|
||||
if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
|
||||
else dsp->sb_16_enable = dsp->sbenable = 0;
|
||||
sb_irq(dsp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r)
|
||||
{
|
||||
*l = dsp->sbdatl;
|
||||
*r = dsp->sbdatr;
|
||||
}
|
||||
69
src/sound_sb_dsp.h
Normal file
69
src/sound_sb_dsp.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
typedef struct sb_dsp_t
|
||||
{
|
||||
int sb_type;
|
||||
|
||||
int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output;
|
||||
int sb_8_dmanum;
|
||||
int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output;
|
||||
int sb_pausetime;
|
||||
|
||||
uint8_t sb_read_data[256];
|
||||
int sb_read_wp, sb_read_rp;
|
||||
int sb_speaker;
|
||||
|
||||
int sb_data_stat;
|
||||
|
||||
int sb_irqnum;
|
||||
|
||||
uint8_t sbe2;
|
||||
int sbe2count;
|
||||
|
||||
uint8_t sb_data[8];
|
||||
|
||||
int sb_freq;
|
||||
|
||||
int writebusy; /*Needed for Amnesia*/
|
||||
|
||||
int16_t sbdat;
|
||||
int sbdat2;
|
||||
int16_t sbdatl, sbdatr;
|
||||
|
||||
uint8_t sbref;
|
||||
int8_t sbstep;
|
||||
|
||||
int sbdacpos;
|
||||
|
||||
int sbleftright;
|
||||
|
||||
int sbreset;
|
||||
uint8_t sbreaddat;
|
||||
uint8_t sb_command;
|
||||
uint8_t sb_test;
|
||||
int sb_timei, sb_timeo;
|
||||
|
||||
int sb_irq8, sb_irq16;
|
||||
|
||||
uint8_t sb_asp_regs[256];
|
||||
|
||||
int sbenable, sb_enable_i;
|
||||
|
||||
int sbcount, sb_count_i;
|
||||
|
||||
int sblatcho, sblatchi;
|
||||
|
||||
uint16_t sb_addr;
|
||||
|
||||
int stereo;
|
||||
} sb_dsp_t;
|
||||
|
||||
void sb_dsp_init(sb_dsp_t *dsp, int type);
|
||||
|
||||
void sb_dsp_setirq(sb_dsp_t *dsp, int irq);
|
||||
void sb_dsp_setdma8(sb_dsp_t *dsp, int dma);
|
||||
void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr);
|
||||
|
||||
void sb_dsp_speed_changed(sb_dsp_t *dsp);
|
||||
|
||||
void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r);
|
||||
|
||||
void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo);
|
||||
198
src/sound_sn76489.c
Normal file
198
src/sound_sn76489.c
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "device.h"
|
||||
#include "io.h"
|
||||
#include "sound.h"
|
||||
#include "sound_sn76489.h"
|
||||
|
||||
static float volslog[16]=
|
||||
{
|
||||
0.00000f,0.59715f,0.75180f,0.94650f,
|
||||
1.19145f,1.50000f,1.88835f,2.37735f,
|
||||
2.99295f,3.76785f,4.74345f,5.97165f,
|
||||
7.51785f,9.46440f,11.9194f,15.0000f
|
||||
};
|
||||
|
||||
typedef struct sn76489_t
|
||||
{
|
||||
int stat[4];
|
||||
int latch[4], count[4];
|
||||
int freqlo[4], freqhi[4];
|
||||
int vol[4];
|
||||
uint32_t shift;
|
||||
uint8_t noise;
|
||||
int lasttone;
|
||||
uint8_t firstdat;
|
||||
|
||||
int16_t buffer[SOUNDBUFLEN];
|
||||
int pos;
|
||||
} sn76489_t;
|
||||
|
||||
#define PSGCONST ((3579545.0 / 64.0) / 48000.0)
|
||||
|
||||
void sn76489_poll(void *p)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *)p;
|
||||
int c;
|
||||
int16_t result = 0;
|
||||
|
||||
if (sn76489->pos >= SOUNDBUFLEN)
|
||||
return;
|
||||
|
||||
for (c = 1; c < 4; c++)
|
||||
{
|
||||
if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]);
|
||||
else result += (int16_t) (volslog[sn76489->vol[c]] * 127);
|
||||
|
||||
sn76489->count[c] -= (256 * PSGCONST);
|
||||
while ((int)sn76489->count[c] < 0 && sn76489->latch[c])
|
||||
{
|
||||
sn76489->count[c] += sn76489->latch[c];
|
||||
sn76489->stat[c] = -sn76489->stat[c];
|
||||
}
|
||||
}
|
||||
result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2);
|
||||
|
||||
sn76489->count[0] -= (512 * PSGCONST);
|
||||
while ((int)sn76489->count[0] < 0 && sn76489->latch[0])
|
||||
{
|
||||
sn76489->count[0] += (sn76489->latch[0] * 2);
|
||||
if (!(sn76489->noise & 4))
|
||||
{
|
||||
if (sn76489->shift & 1)
|
||||
sn76489->shift |= 0x8000;
|
||||
sn76489->shift >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1))
|
||||
sn76489->shift |= 0x8000;
|
||||
sn76489->shift >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
sn76489->buffer[sn76489->pos++] = result;
|
||||
}
|
||||
|
||||
void sn76489_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *)p;
|
||||
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
buffer[c] += sn76489->buffer[c >> 1];
|
||||
|
||||
sn76489->pos = 0;
|
||||
}
|
||||
|
||||
void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *)p;
|
||||
int freq;
|
||||
|
||||
if (data & 0x80)
|
||||
{
|
||||
sn76489->firstdat = data;
|
||||
switch (data & 0x70)
|
||||
{
|
||||
case 0:
|
||||
sn76489->freqlo[3] = data & 0xf;
|
||||
sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6;
|
||||
sn76489->lasttone = 3;
|
||||
break;
|
||||
case 0x10:
|
||||
data &= 0xf;
|
||||
sn76489->vol[3] = 0xf - data;
|
||||
break;
|
||||
case 0x20:
|
||||
sn76489->freqlo[2] = data & 0xf;
|
||||
sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6;
|
||||
sn76489->lasttone = 2;
|
||||
break;
|
||||
case 0x30:
|
||||
data &= 0xf;
|
||||
sn76489->vol[2] = 0xf - data;
|
||||
break;
|
||||
case 0x40:
|
||||
sn76489->freqlo[1] = data & 0xf;
|
||||
sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6;
|
||||
sn76489->lasttone = 1;
|
||||
break;
|
||||
case 0x50:
|
||||
data &= 0xf;
|
||||
sn76489->vol[1] = 0xf - data;
|
||||
break;
|
||||
case 0x60:
|
||||
sn76489->shift = 0x4000;
|
||||
if ((data & 3) != (sn76489->noise & 3)) sn76489->count[0] = 0;
|
||||
sn76489->noise = data & 0xf;
|
||||
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
||||
else sn76489->latch[0] = 0x400 << (data & 3);
|
||||
break;
|
||||
case 0x70:
|
||||
data &= 0xf;
|
||||
sn76489->vol[0] = 0xf - data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sn76489->firstdat & 0x70) == 0x60)
|
||||
{
|
||||
sn76489->shift = 0x4000;
|
||||
if ((data & 3) != (sn76489->noise & 3))
|
||||
sn76489->count[0] = 0;
|
||||
sn76489->noise = data & 0xf;
|
||||
if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1];
|
||||
else sn76489->latch[0] = 0x400 << (data & 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
sn76489->freqhi[sn76489->lasttone] = data & 0x3F;
|
||||
freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4);
|
||||
if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1)
|
||||
sn76489->latch[0] = freq << 6;
|
||||
sn76489->latch[sn76489->lasttone] = freq << 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *sn76489_init()
|
||||
{
|
||||
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
||||
memset(sn76489, 0, sizeof(sn76489_t));
|
||||
|
||||
io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489);
|
||||
|
||||
sound_add_handler(sn76489_poll, sn76489_get_buffer, sn76489);
|
||||
|
||||
sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6;
|
||||
sn76489->vol[0] = 0;
|
||||
sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8;
|
||||
sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127;
|
||||
srand(time(NULL));
|
||||
sn76489->count[0] = 0;
|
||||
sn76489->count[1] = (rand()&0x3FF)<<6;
|
||||
sn76489->count[2] = (rand()&0x3FF)<<6;
|
||||
sn76489->count[3] = (rand()&0x3FF)<<6;
|
||||
sn76489->noise = 3;
|
||||
sn76489->shift = 0x4000;
|
||||
|
||||
return sn76489;
|
||||
}
|
||||
|
||||
void sn76489_close(void *p)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *)p;
|
||||
|
||||
free(sn76489);
|
||||
}
|
||||
|
||||
device_t sn76489_device =
|
||||
{
|
||||
"TI SN74689 PSG",
|
||||
sn76489_init,
|
||||
sn76489_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_sn76489.h
Normal file
1
src/sound_sn76489.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t sn76489_device;
|
||||
42
src/sound_speaker.c
Normal file
42
src/sound_speaker.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include "ibm.h"
|
||||
#include "sound.h"
|
||||
#include "sound_speaker.h"
|
||||
|
||||
static int16_t speaker_buffer[SOUNDBUFLEN];
|
||||
|
||||
static int speaker_pos = 0;
|
||||
|
||||
int wasgated = 0;
|
||||
|
||||
static void speaker_poll(void *p)
|
||||
{
|
||||
if (speaker_pos >= SOUNDBUFLEN) return;
|
||||
|
||||
// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]);
|
||||
if (gated)
|
||||
{
|
||||
if (!pit.m[2] || pit.m[2]==4)
|
||||
speaker_buffer[speaker_pos] = speakval;
|
||||
else
|
||||
speaker_buffer[speaker_pos] = speakon ? 0x1400 : 0;
|
||||
}
|
||||
else
|
||||
speaker_buffer[speaker_pos] = wasgated ? 0x1400 : 0;
|
||||
speaker_pos++;
|
||||
wasgated = 0;
|
||||
}
|
||||
|
||||
static void speaker_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
buffer[c] += speaker_buffer[c >> 1];
|
||||
|
||||
speaker_pos = 0;
|
||||
}
|
||||
|
||||
void speaker_init()
|
||||
{
|
||||
sound_add_handler(speaker_poll, speaker_get_buffer, NULL);
|
||||
}
|
||||
1
src/sound_speaker.h
Normal file
1
src/sound_speaker.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void speaker_init();
|
||||
307
src/sound_wss.c
Normal file
307
src/sound_wss.c
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*PCem v0.8 by Tom Walker
|
||||
|
||||
Windows Sound System compatible CODEC emulation (AD1848)*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "dma.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "sound_opl.h"
|
||||
#include "sound_wss.h"
|
||||
|
||||
/*530, 11, 3 - 530=23*/
|
||||
/*530, 11, 1 - 530=22*/
|
||||
/*530, 11, 0 - 530=21*/
|
||||
/*530, 10, 1 - 530=1a*/
|
||||
/*530, 9, 1 - 530=12*/
|
||||
/*530, 7, 1 - 530=0a*/
|
||||
/*604, 11, 1 - 530=22*/
|
||||
/*e80, 11, 1 - 530=22*/
|
||||
/*f40, 11, 1 - 530=22*/
|
||||
|
||||
|
||||
static int wss_dma[4] = {0, 0, 1, 3};
|
||||
static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/
|
||||
static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40};
|
||||
|
||||
typedef struct wss_t
|
||||
{
|
||||
uint8_t config;
|
||||
|
||||
int index;
|
||||
uint8_t regs[16];
|
||||
uint8_t status;
|
||||
|
||||
int trd;
|
||||
int mce;
|
||||
|
||||
int count;
|
||||
|
||||
int16_t out_l, out_r;
|
||||
|
||||
int interp_count, inc;
|
||||
|
||||
int enable;
|
||||
|
||||
int irq, dma;
|
||||
|
||||
opl_t opl;
|
||||
|
||||
int16_t opl_buffer[SOUNDBUFLEN * 2];
|
||||
int16_t pcm_buffer[2][SOUNDBUFLEN];
|
||||
|
||||
int pos;
|
||||
} wss_t;
|
||||
|
||||
static int wss_vols[64];
|
||||
|
||||
uint8_t wss_read(uint16_t addr, void *p)
|
||||
{
|
||||
wss_t *wss = (wss_t *)p;
|
||||
uint8_t temp = 0xff;
|
||||
// pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc);
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 0: case 1: case 2: case 3: /*Version*/
|
||||
temp = 4 | (wss->config & 0x40);
|
||||
break;
|
||||
|
||||
case 4: /*Index*/
|
||||
temp = wss->index | wss->trd | wss->mce;
|
||||
break;
|
||||
case 5:
|
||||
temp = wss->regs[wss->index];
|
||||
break;
|
||||
case 6:
|
||||
temp = wss->status;
|
||||
break;
|
||||
}
|
||||
// pclog("return %02X\n", temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void wss_write(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
wss_t *wss = (wss_t *)p;
|
||||
double freq;
|
||||
pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc);
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 0: case 1: case 2: case 3: /*Config*/
|
||||
wss->config = val;
|
||||
wss->dma = wss_dma[val & 3];
|
||||
wss->irq = wss_irq[(val >> 3) & 7];
|
||||
break;
|
||||
|
||||
case 4: /*Index*/
|
||||
wss->index = val & 0xf;
|
||||
wss->trd = val & 0x20;
|
||||
wss->mce = val & 0x40;
|
||||
break;
|
||||
case 5:
|
||||
switch (wss->index)
|
||||
{
|
||||
case 8:
|
||||
freq = (val & 1) ? 16934400 : 24576000;
|
||||
switch ((val >> 1) & 7)
|
||||
{
|
||||
case 0: freq /= 3072; break;
|
||||
case 1: freq /= 1536; break;
|
||||
case 2: freq /= 896; break;
|
||||
case 3: freq /= 768; break;
|
||||
case 4: freq /= 448; break;
|
||||
case 5: freq /= 384; break;
|
||||
case 6: freq /= 512; break;
|
||||
case 7: freq /= 2560; break;
|
||||
}
|
||||
wss->inc = (int)((freq * 65536) / 48000);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
if (!wss->enable)
|
||||
wss->interp_count = 0;
|
||||
|
||||
wss->enable = ((val & 0x41) == 0x01);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
return;
|
||||
|
||||
case 14:
|
||||
wss->count = wss->regs[15] | (val << 8);
|
||||
break;
|
||||
}
|
||||
wss->regs[wss->index] = val;
|
||||
break;
|
||||
case 6:
|
||||
wss->status &= 0xfe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wss_poll(void *p)
|
||||
{
|
||||
wss_t *wss = (wss_t *)p;
|
||||
|
||||
if (wss->pos >= SOUNDBUFLEN)
|
||||
return;
|
||||
|
||||
opl3_poll(&wss->opl, &wss->opl_buffer[wss->pos * 2], &wss->opl_buffer[(wss->pos * 2) + 1]);
|
||||
|
||||
if (wss->enable)
|
||||
{
|
||||
int32_t temp;
|
||||
|
||||
if (wss->regs[6] & 0x80)
|
||||
wss->pcm_buffer[1][wss->pos] = 0;
|
||||
else
|
||||
wss->pcm_buffer[1][wss->pos] = (wss->out_l * wss_vols[wss->regs[6] & 0x3f]) >> 16;
|
||||
|
||||
if (wss->regs[7] & 0x80)
|
||||
wss->pcm_buffer[0][wss->pos] = 0;
|
||||
else
|
||||
wss->pcm_buffer[0][wss->pos] = (wss->out_r * wss_vols[wss->regs[7] & 0x3f]) >> 16;
|
||||
|
||||
wss->interp_count += wss->inc;
|
||||
if (wss->interp_count >= 0x10000)
|
||||
{
|
||||
wss->interp_count -= 0x10000;
|
||||
|
||||
if (wss->count < 0)
|
||||
{
|
||||
wss->count = wss->regs[15] | (wss->regs[14] << 8);
|
||||
if (!(wss->status & 0x01))
|
||||
{
|
||||
wss->status |= 0x01;
|
||||
if (wss->regs[0xa] & 2)
|
||||
picint(1 << wss->irq);
|
||||
}
|
||||
}
|
||||
|
||||
switch (wss->regs[8] & 0x70)
|
||||
{
|
||||
case 0x00: /*Mono, 8-bit PCM*/
|
||||
wss->out_l = wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
case 0x10: /*Stereo, 8-bit PCM*/
|
||||
wss->out_l = (dma_channel_read(wss->dma) ^ 0x80) * 256;
|
||||
wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256;
|
||||
break;
|
||||
|
||||
case 0x40: /*Mono, 16-bit PCM*/
|
||||
temp = dma_channel_read(wss->dma);
|
||||
wss->out_l = wss->out_r = dma_channel_read(wss->dma) | (temp << 8);
|
||||
break;
|
||||
case 0x50: /*Stereo, 16-bit PCM*/
|
||||
temp = dma_channel_read(wss->dma);
|
||||
wss->out_l = dma_channel_read(wss->dma) | (temp << 8);
|
||||
temp = dma_channel_read(wss->dma);
|
||||
wss->out_r = dma_channel_read(wss->dma) | (temp << 8);
|
||||
break;
|
||||
}
|
||||
|
||||
wss->count--;
|
||||
}
|
||||
// pclog("wss_poll : enable %X %X %X %X %X %X\n", wss->pcm_buffer[0][wss->pos], wss->pcm_buffer[1][wss->pos], wss->out_l[0], wss->out_r[0], wss->out_l[1], wss->out_r[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
wss->pcm_buffer[0][wss->pos] = wss->pcm_buffer[1][wss->pos] = 0;
|
||||
// pclog("wss_poll : not enable\n");
|
||||
}
|
||||
wss->pos++;
|
||||
}
|
||||
|
||||
static void wss_get_buffer(int16_t *buffer, int len, void *p)
|
||||
{
|
||||
wss_t *wss = (wss_t *)p;
|
||||
|
||||
int c;
|
||||
|
||||
for (c = 0; c < len * 2; c++)
|
||||
{
|
||||
buffer[c] += wss->opl_buffer[c];
|
||||
buffer[c] += (wss->pcm_buffer[c & 1][c >> 1] / 2);
|
||||
}
|
||||
|
||||
wss->pos = 0;
|
||||
}
|
||||
|
||||
void *wss_init()
|
||||
{
|
||||
wss_t *wss = malloc(sizeof(wss_t));
|
||||
int c;
|
||||
double attenuation;
|
||||
|
||||
memset(wss, 0, sizeof(wss_t));
|
||||
|
||||
opl3_init(&wss->opl);
|
||||
|
||||
pclog("wss_init - %i %i\n", sbtype, SND_WSS);
|
||||
|
||||
wss->enable = 0;
|
||||
|
||||
wss->status = 0xcc;
|
||||
wss->index = wss->trd = 0;
|
||||
wss->mce = 0x40;
|
||||
|
||||
wss->regs[0] = wss->regs[1] = 0;
|
||||
wss->regs[2] = wss->regs[3] = 0x80;
|
||||
wss->regs[4] = wss->regs[5] = 0x80;
|
||||
wss->regs[6] = wss->regs[7] = 0x80;
|
||||
wss->regs[8] = 0;
|
||||
wss->regs[9] = 0x08;
|
||||
wss->regs[10] = wss->regs[11] = 0;
|
||||
wss->regs[12] = 0xa;
|
||||
wss->regs[13] = 0;
|
||||
wss->regs[14] = wss->regs[15] = 0;
|
||||
|
||||
wss->out_l = 0;
|
||||
wss->out_r = 0;
|
||||
wss->interp_count = 0;
|
||||
|
||||
wss->irq = 7;
|
||||
wss->dma = 3;
|
||||
|
||||
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
|
||||
io_sethandler(0x0530, 0x0008, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
|
||||
|
||||
sound_add_handler(wss_poll, wss_get_buffer, wss);
|
||||
|
||||
for (c = 0; c < 64; c++)
|
||||
{
|
||||
attenuation = 0.0;
|
||||
if (c & 0x01) attenuation -= 1.5;
|
||||
if (c & 0x02) attenuation -= 3.0;
|
||||
if (c & 0x04) attenuation -= 6.0;
|
||||
if (c & 0x08) attenuation -= 12.0;
|
||||
if (c & 0x10) attenuation -= 24.0;
|
||||
if (c & 0x20) attenuation -= 48.0;
|
||||
|
||||
attenuation = pow(10, attenuation / 10);
|
||||
|
||||
wss_vols[c] = (int)(attenuation * 65536);
|
||||
pclog("wss_vols %i = %f %i\n", c, attenuation, wss_vols[c]);
|
||||
}
|
||||
|
||||
return wss;
|
||||
}
|
||||
|
||||
void wss_close(void *p)
|
||||
{
|
||||
wss_t *wss = (wss_t *)p;
|
||||
|
||||
free(wss);
|
||||
}
|
||||
|
||||
device_t wss_device =
|
||||
{
|
||||
"Windows Sound System",
|
||||
wss_init,
|
||||
wss_close,
|
||||
NULL
|
||||
};
|
||||
1
src/sound_wss.h
Normal file
1
src/sound_wss.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern device_t wss_device;
|
||||
94
src/timer.c
Normal file
94
src/timer.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include "ibm.h"
|
||||
|
||||
/*#include "sound_opl.h"
|
||||
#include "adlibgold.h"
|
||||
#include "sound_pas16.h"
|
||||
#include "sound_sb.h"
|
||||
#include "sound_sb_dsp.h"
|
||||
#include "sound_wss.h"*/
|
||||
#include "timer.h"
|
||||
|
||||
#define TIMERS_MAX 32
|
||||
|
||||
int TIMER_USEC;
|
||||
|
||||
static struct
|
||||
{
|
||||
int present;
|
||||
void (*callback)(void *priv);
|
||||
void *priv;
|
||||
int *enable;
|
||||
int *count;
|
||||
} timers[TIMERS_MAX];
|
||||
|
||||
int timers_present = 0;
|
||||
int timer_one = 1;
|
||||
|
||||
int timer_count = 0, timer_latch = 0;
|
||||
|
||||
void timer_process()
|
||||
{
|
||||
int c;
|
||||
|
||||
/*Get actual elapsed time*/
|
||||
timer_latch -= timer_count;
|
||||
|
||||
for (c = 0; c < timers_present; c++)
|
||||
{
|
||||
// pclog("timer_process : %i enable %i %X\n", c, timers[c].enable, *timers[c].enable);
|
||||
if (*timers[c].enable)
|
||||
{
|
||||
*timers[c].count = *timers[c].count - (timer_latch << TIMER_SHIFT);
|
||||
if (*timers[c].count <= 0)
|
||||
{
|
||||
timers[c].callback(timers[c].priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void timer_update_outstanding()
|
||||
{
|
||||
int c;
|
||||
timer_latch = 0x7fffffff;
|
||||
for (c = 0; c < timers_present; c++)
|
||||
{
|
||||
if (*timers[c].enable && *timers[c].count < timer_latch)
|
||||
timer_latch = *timers[c].count;
|
||||
}
|
||||
if (spktime < timer_latch) timer_latch = spktime;
|
||||
//if (soundtime < timer_latch) timer_latch = soundtime;
|
||||
//if (gustime < timer_latch) timer_latch = gustime;
|
||||
//if (gustime2 < timer_latch) timer_latch = gustime2;
|
||||
//if (vidtime < timer_latch) timer_latch = vidtime;
|
||||
timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)) >> TIMER_SHIFT;
|
||||
}
|
||||
|
||||
void timer_reset()
|
||||
{
|
||||
pclog("timer_reset\n");
|
||||
timers_present = 0;
|
||||
timer_latch = timer_count = 0;
|
||||
// timer_process();
|
||||
}
|
||||
|
||||
int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv)
|
||||
{
|
||||
if (timers_present < TIMERS_MAX)
|
||||
{
|
||||
pclog("timer_add : adding timer %i\n", timers_present);
|
||||
timers[timers_present].present = 1;
|
||||
timers[timers_present].callback = callback;
|
||||
timers[timers_present].priv = priv;
|
||||
timers[timers_present].count = count;
|
||||
timers[timers_present].enable = enable;
|
||||
timers_present++;
|
||||
return timers_present - 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void timer_set_callback(int timer, void (*callback)(void *priv))
|
||||
{
|
||||
timers[timer].callback = callback;
|
||||
}
|
||||
25
src/timer.h
Normal file
25
src/timer.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#define timer_clock(cycles) \
|
||||
do \
|
||||
{ \
|
||||
timer_count -= cycles; \
|
||||
if (timer_count <= 0) \
|
||||
{ \
|
||||
timer_process(); \
|
||||
timer_update_outstanding(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void timer_process();
|
||||
void timer_update_outstanding();
|
||||
void timer_reset();
|
||||
int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv);
|
||||
void timer_set_callback(int timer, void (*callback)(void *priv));
|
||||
|
||||
#define TIMER_ALWAYS_ENABLED &timer_one
|
||||
|
||||
extern int timer_count;
|
||||
extern int timer_one;
|
||||
|
||||
#define TIMER_SHIFT 6
|
||||
|
||||
extern int TIMER_USEC;
|
||||
138
src/um8669f.c
Normal file
138
src/um8669f.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*um8669f :
|
||||
|
||||
aa to 108 unlocks
|
||||
next 108 write is register select (Cx?)
|
||||
data read/write to 109
|
||||
55 to 108 locks
|
||||
|
||||
|
||||
|
||||
|
||||
C0
|
||||
bit 3 = LPT1 enable
|
||||
bit 2 = COM2 enable
|
||||
bit 1 = COM1 enable
|
||||
bit 0 = FDC enable
|
||||
|
||||
C1
|
||||
bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP
|
||||
bit 3 = clear when LPT1 = 278
|
||||
|
||||
C3
|
||||
bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP
|
||||
bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7
|
||||
|
||||
COM1 :
|
||||
3f8, IRQ4 - C1 = BF, C3 = 00
|
||||
2f8, IRQ3 - C1 = BF, C3 = 03
|
||||
3e8, IRQ4 - C1 = BD, C3 = 00
|
||||
2e8, IRQ3 - B1 = BD, C3 = 03
|
||||
|
||||
COM2 :
|
||||
3f8, IRQ4 - C1 = BF, C3 = 0C
|
||||
2f8, IRQ3 - C1 = BF, C3 = 00
|
||||
3e8, IRQ4 - C1 = BB, C3 = 0C
|
||||
2e8, IRQ3 - C1 = BB, C3 = 00
|
||||
|
||||
*/
|
||||
|
||||
#include "ibm.h"
|
||||
|
||||
#include "fdc.h"
|
||||
#include "io.h"
|
||||
#include "lpt.h"
|
||||
#include "mouse_serial.h"
|
||||
#include "serial.h"
|
||||
#include "um8669f.h"
|
||||
|
||||
static int um8669f_locked;
|
||||
static int um8669f_curreg;
|
||||
static uint8_t um8669f_regs[256];
|
||||
|
||||
void um8669f_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
int temp;
|
||||
if (um8669f_locked)
|
||||
{
|
||||
if (port == 0x108 && val == 0xaa)
|
||||
um8669f_locked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port == 0x108)
|
||||
{
|
||||
if (val == 0x55)
|
||||
um8669f_locked = 1;
|
||||
else
|
||||
um8669f_curreg = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
um8669f_regs[um8669f_curreg] = val;
|
||||
pclog("um8669f_write : reg %02X = %02X\n", um8669f_curreg, val);
|
||||
|
||||
fdc_remove();
|
||||
if (um8669f_regs[0xc0] & 1)
|
||||
fdc_add();
|
||||
|
||||
serial1_remove();
|
||||
if (um8669f_regs[0xc0] & 2)
|
||||
{
|
||||
temp = um8669f_regs[0xc3] & 1; /*might be & 2*/
|
||||
if (!(um8669f_regs[0xc1] & 2))
|
||||
temp |= 2;
|
||||
switch (temp)
|
||||
{
|
||||
case 0: serial1_init(0x3f8); break;
|
||||
case 1: serial1_init(0x2f8); break;
|
||||
case 2: serial1_init(0x3e8); break;
|
||||
case 3: serial1_init(0x2e8); break;
|
||||
}
|
||||
}
|
||||
|
||||
serial2_remove();
|
||||
if (um8669f_regs[0xc0] & 4)
|
||||
{
|
||||
temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/
|
||||
if (!(um8669f_regs[0xc1] & 4))
|
||||
temp |= 2;
|
||||
switch (temp)
|
||||
{
|
||||
case 0: serial2_init(0x3f8); break;
|
||||
case 1: serial2_init(0x2f8); break;
|
||||
case 2: serial2_init(0x3e8); break;
|
||||
case 3: serial2_init(0x2e8); break;
|
||||
}
|
||||
}
|
||||
|
||||
mouse_serial_init();
|
||||
|
||||
lpt1_remove();
|
||||
lpt2_remove();
|
||||
temp = (um8669f_regs[0xc3] >> 4) & 3;
|
||||
switch (temp)
|
||||
{
|
||||
case 0: lpt1_init(0x378); break;
|
||||
case 1: lpt1_init(0x3bc); break;
|
||||
case 2: lpt1_init(0x278); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t um8669f_read(uint16_t port, void *priv)
|
||||
{
|
||||
if (um8669f_locked)
|
||||
return 0xff;
|
||||
|
||||
if (port == 0x108)
|
||||
return um8669f_curreg; /*???*/
|
||||
else
|
||||
return um8669f_regs[um8669f_curreg];
|
||||
}
|
||||
|
||||
void um8669f_init()
|
||||
{
|
||||
io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL);
|
||||
um8669f_locked = 1;
|
||||
}
|
||||
1
src/um8669f.h
Normal file
1
src/um8669f.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
extern void um8669f_init();
|
||||
142
src/vid_ati18800.c
Normal file
142
src/vid_ati18800.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*ATI 18800 emulation (VGA Edge-16)*/
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "video.h"
|
||||
#include "vid_ati_eeprom.h"
|
||||
#include "vid_svga.h"
|
||||
|
||||
static uint8_t ati_regs[256];
|
||||
static int ati_index;
|
||||
|
||||
void ati18800_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
pclog("ati18800_out : %04X %02X %04X:%04X\n", addr, val, CS,pc);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1ce:
|
||||
ati_index = val;
|
||||
break;
|
||||
case 0x1cf:
|
||||
ati_regs[ati_index] = val;
|
||||
switch (ati_index)
|
||||
{
|
||||
case 0xb2:
|
||||
case 0xbe:
|
||||
if (ati_regs[0xbe] & 8) /*Read/write bank mode*/
|
||||
{
|
||||
svgarbank = ((ati_regs[0xb2] >> 5) & 7) * 0x10000;
|
||||
svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000;
|
||||
}
|
||||
else /*Single bank mode*/
|
||||
svgarbank = svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000;
|
||||
break;
|
||||
case 0xb3:
|
||||
ati_eeprom_write(val & 8, val & 2, val & 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
crtcreg = val & 0x3f;
|
||||
return;
|
||||
case 0x3D5:
|
||||
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
||||
old=crtc[crtcreg];
|
||||
crtc[crtcreg]=val;
|
||||
if (old!=val)
|
||||
{
|
||||
if (crtcreg<0xE || crtcreg>0x10)
|
||||
{
|
||||
fullchange=changeframecount;
|
||||
svga_recalctimings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
svga_out(addr, val, NULL);
|
||||
}
|
||||
|
||||
uint8_t ati18800_in(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
if (addr != 0x3da) pclog("ati18800_in : %04X ", addr);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1ce:
|
||||
temp = ati_index;
|
||||
break;
|
||||
case 0x1cf:
|
||||
switch (ati_index)
|
||||
{
|
||||
case 0xb7:
|
||||
temp = ati_regs[ati_index] & ~8;
|
||||
if (ati_eeprom_read())
|
||||
temp |= 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
temp = ati_regs[ati_index];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
temp = crtcreg;
|
||||
break;
|
||||
case 0x3D5:
|
||||
temp = crtc[crtcreg];
|
||||
break;
|
||||
default:
|
||||
temp = svga_in(addr, NULL);
|
||||
break;
|
||||
}
|
||||
if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc);
|
||||
return temp;
|
||||
}
|
||||
|
||||
int ati18800_init()
|
||||
{
|
||||
svga_recalctimings_ex = NULL;
|
||||
svga_vram_limit = 1 << 19; /*512kb*/
|
||||
vrammask = 0x7ffff;
|
||||
svgawbank = svgarbank = 0;
|
||||
bpp = 8;
|
||||
svga_miscout = 1;
|
||||
|
||||
io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, NULL);
|
||||
|
||||
ati_eeprom_load("ati18800.nvr", 0);
|
||||
|
||||
return svga_init();
|
||||
}
|
||||
|
||||
GFXCARD vid_ati18800 =
|
||||
{
|
||||
ati18800_init,
|
||||
/*IO at 3Cx/3Dx*/
|
||||
ati18800_out,
|
||||
ati18800_in,
|
||||
/*IO at 3Ax/3Bx*/
|
||||
video_out_null,
|
||||
video_in_null,
|
||||
|
||||
svga_poll,
|
||||
svga_recalctimings,
|
||||
|
||||
svga_write,
|
||||
video_write_null,
|
||||
video_write_null,
|
||||
|
||||
svga_read,
|
||||
video_read_null,
|
||||
video_read_null
|
||||
};
|
||||
161
src/vid_ati28800.c
Normal file
161
src/vid_ati28800.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*ATI 28800 emulation (VGA Charger)*/
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "video.h"
|
||||
#include "vid_ati_eeprom.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_svga_render.h"
|
||||
|
||||
static uint8_t ati_regs[256];
|
||||
static int ati_index;
|
||||
|
||||
void ati28800_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
pclog("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS,pc);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1ce:
|
||||
ati_index = val;
|
||||
break;
|
||||
case 0x1cf:
|
||||
ati_regs[ati_index] = val;
|
||||
switch (ati_index)
|
||||
{
|
||||
case 0xb2:
|
||||
case 0xbe:
|
||||
if (ati_regs[0xbe] & 8) /*Read/write bank mode*/
|
||||
{
|
||||
svgarbank = ((ati_regs[0xb2] >> 5) & 7) * 0x10000;
|
||||
svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000;
|
||||
}
|
||||
else /*Single bank mode*/
|
||||
svgarbank = svgawbank = ((ati_regs[0xb2] >> 1) & 7) * 0x10000;
|
||||
break;
|
||||
case 0xb3:
|
||||
ati_eeprom_write(val & 8, val & 2, val & 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
crtcreg = val & 0x3f;
|
||||
return;
|
||||
case 0x3D5:
|
||||
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
||||
old=crtc[crtcreg];
|
||||
crtc[crtcreg]=val;
|
||||
if (old!=val)
|
||||
{
|
||||
if (crtcreg<0xE || crtcreg>0x10)
|
||||
{
|
||||
fullchange=changeframecount;
|
||||
svga_recalctimings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
svga_out(addr, val, NULL);
|
||||
}
|
||||
|
||||
uint8_t ati28800_in(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
if (addr != 0x3da) pclog("ati28800_in : %04X ", addr);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1ce:
|
||||
temp = ati_index;
|
||||
break;
|
||||
case 0x1cf:
|
||||
switch (ati_index)
|
||||
{
|
||||
case 0xb7:
|
||||
temp = ati_regs[ati_index] & ~8;
|
||||
if (ati_eeprom_read())
|
||||
temp |= 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
temp = ati_regs[ati_index];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3c2:
|
||||
if ((vgapal[0].r + vgapal[0].g + vgapal[0].b) >= 0x50)
|
||||
temp = 0;
|
||||
else
|
||||
temp = 0x10;
|
||||
break;
|
||||
case 0x3D4:
|
||||
temp = crtcreg;
|
||||
break;
|
||||
case 0x3D5:
|
||||
temp = crtc[crtcreg];
|
||||
break;
|
||||
default:
|
||||
temp = svga_in(addr, NULL);
|
||||
break;
|
||||
}
|
||||
if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void ati28800_recalctimings()
|
||||
{
|
||||
pclog("ati28800_recalctimings\n");
|
||||
if (!scrblank && (ati_regs[0xb0] & 0x20)) /*Extended 256 colour modes*/
|
||||
{
|
||||
pclog("8bpp_highres\n");
|
||||
svga_render = svga_render_8bpp_highres;
|
||||
svga_rowoffset <<= 1;
|
||||
svga_ma <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
int ati28800_init()
|
||||
{
|
||||
svga_recalctimings_ex = ati28800_recalctimings;
|
||||
svga_vram_limit = 1 << 19; /*512kb*/
|
||||
vrammask = 0x7ffff;
|
||||
svgawbank = svgarbank = 0;
|
||||
bpp = 8;
|
||||
svga_miscout = 1;
|
||||
|
||||
io_sethandler(0x01ce, 0x0002, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, NULL);
|
||||
|
||||
ati_eeprom_load("ati28800.nvr", 0);
|
||||
|
||||
return svga_init();
|
||||
}
|
||||
|
||||
GFXCARD vid_ati28800 =
|
||||
{
|
||||
ati28800_init,
|
||||
/*IO at 3Cx/3Dx*/
|
||||
ati28800_out,
|
||||
ati28800_in,
|
||||
/*IO at 3Ax/3Bx*/
|
||||
video_out_null,
|
||||
video_in_null,
|
||||
|
||||
svga_poll,
|
||||
svga_recalctimings,
|
||||
|
||||
svga_write,
|
||||
video_write_null,
|
||||
video_write_null,
|
||||
|
||||
svga_read,
|
||||
video_read_null,
|
||||
video_read_null
|
||||
};
|
||||
83
src/vid_ati68860_ramdac.c
Normal file
83
src/vid_ati68860_ramdac.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*ATI 68860 RAMDAC emulation (for Mach64)*/
|
||||
/*
|
||||
ATI 68860/68880 Truecolor DACs:
|
||||
REG08 (R/W):
|
||||
bit 0-? Always 2 ??
|
||||
|
||||
REG0A (R/W):
|
||||
bit 0-? Always 1Dh ??
|
||||
|
||||
REG0B (R/W): (GMR ?)
|
||||
bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, A0h: 15bpp, A1h: 16bpp, C0h: 24bpp,
|
||||
E3h: 32bpp (80h for VGA modes ?)
|
||||
|
||||
REG0C (R/W): Device Setup Register A
|
||||
bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT
|
||||
2-3 Depends on Video memory (= VRAM width ?) . 1: Less than 1Mb, 2: 1Mb,
|
||||
3: > 1Mb
|
||||
5-6 Always set ?
|
||||
7 If set can remove "snow" in some cases (A860_Delay_L ?) ??
|
||||
*/
|
||||
#include "ibm.h"
|
||||
#include "video.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_ati68860_ramdac.h"
|
||||
|
||||
static uint8_t ramdac_regs[16];
|
||||
void ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
// pclog("ati68860_out : addr %04X val %02X %04X:%04X\n", addr, val, CS,pc);
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
svga_out(0x3c8, val, NULL);
|
||||
break;
|
||||
case 1:
|
||||
svga_out(0x3c9, val, NULL);
|
||||
break;
|
||||
case 2:
|
||||
svga_out(0x3c6, val, NULL);
|
||||
break;
|
||||
case 3:
|
||||
svga_out(0x3c7, val, NULL);
|
||||
break;
|
||||
default:
|
||||
ramdac_regs[addr & 0xf] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ati68860_ramdac_in(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
ret = svga_in(0x3c8, NULL);
|
||||
break;
|
||||
case 1:
|
||||
ret = svga_in(0x3c9, NULL);
|
||||
break;
|
||||
case 2:
|
||||
ret = svga_in(0x3c6, NULL);
|
||||
break;
|
||||
case 3:
|
||||
ret = svga_in(0x3c7, NULL);
|
||||
break;
|
||||
case 4: case 8:
|
||||
ret = 2;
|
||||
break;
|
||||
case 6: case 0xa:
|
||||
ret = 0x1d;
|
||||
break;
|
||||
case 0xf:
|
||||
ret = 0xd0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = ramdac_regs[addr & 0xf];
|
||||
break;
|
||||
}
|
||||
// pclog("ati68860_in : addr %04X ret %02X %04X:%04X\n", addr, ret, CS,pc);
|
||||
return ret;
|
||||
}
|
||||
2
src/vid_ati68860_ramdac.h
Normal file
2
src/vid_ati68860_ramdac.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
void ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv);
|
||||
uint8_t ati68860_ramdac_in(uint16_t addr, void *priv);
|
||||
229
src/vid_ati_eeprom.c
Normal file
229
src/vid_ati_eeprom.c
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
#include "ibm.h"
|
||||
#include "vid_ati_eeprom.h"
|
||||
|
||||
static uint16_t eeprom[256];
|
||||
enum
|
||||
{
|
||||
EEPROM_IDLE,
|
||||
EEPROM_WAIT,
|
||||
EEPROM_OPCODE,
|
||||
EEPROM_INPUT,
|
||||
EEPROM_OUTPUT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EEPROM_OP_EW = 4,
|
||||
EEPROM_OP_WRITE = 5,
|
||||
EEPROM_OP_READ = 6,
|
||||
EEPROM_OP_ERASE = 7,
|
||||
|
||||
EEPROM_OP_WRALMAIN = -1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EEPROM_OP_EWDS = 0,
|
||||
EEPROM_OP_WRAL = 1,
|
||||
EEPROM_OP_ERAL = 2,
|
||||
EEPROM_OP_EWEN = 3
|
||||
};
|
||||
|
||||
static int oldclk, oldena;
|
||||
static int eeprom_opcode, eeprom_state, eeprom_count, eeprom_out;
|
||||
static int eeprom_wp;
|
||||
static uint32_t eeprom_dat;
|
||||
static int eeprom_type;
|
||||
|
||||
static char eeprom_fn[256] = {0};
|
||||
|
||||
void ati_eeprom_load(char *fn, int type)
|
||||
{
|
||||
FILE *f;
|
||||
eeprom_type = type;
|
||||
strcpy(eeprom_fn, fn);
|
||||
f = romfopen(eeprom_fn, "rb");
|
||||
if (!f)
|
||||
{
|
||||
memset(eeprom, 0, type ? 512 : 128);
|
||||
return;
|
||||
}
|
||||
fread(eeprom, 1, type ? 512 : 128, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void ati_eeprom_save()
|
||||
{
|
||||
FILE *f = romfopen(eeprom_fn, "wb");
|
||||
if (!f) return;
|
||||
fwrite(eeprom, 1, eeprom_type ? 512 : 128, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void ati_eeprom_write(int ena, int clk, int dat)
|
||||
{
|
||||
int c;
|
||||
pclog("EEPROM write %i %i %i\n", ena, clk, dat);
|
||||
if (!ena)
|
||||
{
|
||||
eeprom_out = 1;
|
||||
}
|
||||
if (clk && !oldclk)
|
||||
{
|
||||
if (ena && !oldena)
|
||||
{
|
||||
eeprom_state = EEPROM_WAIT;
|
||||
eeprom_opcode = 0;
|
||||
eeprom_count = 3;
|
||||
eeprom_out = 1;
|
||||
}
|
||||
else if (ena)
|
||||
{
|
||||
pclog("EEPROM receive %i %i %i\n", ena, clk, dat);
|
||||
switch (eeprom_state)
|
||||
{
|
||||
case EEPROM_WAIT:
|
||||
if (!dat)
|
||||
break;
|
||||
eeprom_state = EEPROM_OPCODE;
|
||||
/* fall through */
|
||||
case EEPROM_OPCODE:
|
||||
eeprom_opcode = (eeprom_opcode << 1) | (dat ? 1 : 0);
|
||||
eeprom_count--;
|
||||
if (!eeprom_count)
|
||||
{
|
||||
pclog("EEPROM opcode - %i\n", eeprom_opcode);
|
||||
switch (eeprom_opcode)
|
||||
{
|
||||
case EEPROM_OP_WRITE:
|
||||
eeprom_count = eeprom_type ? 24 : 22;
|
||||
eeprom_state = EEPROM_INPUT;
|
||||
eeprom_dat = 0;
|
||||
break;
|
||||
case EEPROM_OP_READ:
|
||||
eeprom_count = eeprom_type ? 8 : 6;
|
||||
eeprom_state = EEPROM_INPUT;
|
||||
eeprom_dat = 0;
|
||||
break;
|
||||
case EEPROM_OP_EW:
|
||||
eeprom_count = 2;
|
||||
eeprom_state = EEPROM_INPUT;
|
||||
eeprom_dat = 0;
|
||||
break;
|
||||
case EEPROM_OP_ERASE:
|
||||
eeprom_count = eeprom_type ? 8 : 6;
|
||||
eeprom_state = EEPROM_INPUT;
|
||||
eeprom_dat = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EEPROM_INPUT:
|
||||
eeprom_dat = (eeprom_dat << 1) | (dat ? 1 : 0);
|
||||
eeprom_count--;
|
||||
if (!eeprom_count)
|
||||
{
|
||||
pclog("EEPROM dat - %02X\n", eeprom_dat);
|
||||
switch (eeprom_opcode)
|
||||
{
|
||||
case EEPROM_OP_WRITE:
|
||||
pclog("EEPROM_OP_WRITE addr %02X eeprom_dat %04X\n", (eeprom_dat >> 16) & (eeprom_type ? 255 : 63), eeprom_dat & 0xffff);
|
||||
if (!eeprom_wp)
|
||||
{
|
||||
eeprom[(eeprom_dat >> 16) & (eeprom_type ? 255 : 63)] = eeprom_dat & 0xffff;
|
||||
ati_eeprom_save();
|
||||
}
|
||||
eeprom_state = EEPROM_IDLE;
|
||||
eeprom_out = 1;
|
||||
break;
|
||||
|
||||
case EEPROM_OP_READ:
|
||||
eeprom_count = 17;
|
||||
eeprom_state = EEPROM_OUTPUT;
|
||||
eeprom_dat = eeprom[eeprom_dat];
|
||||
pclog("Trigger EEPROM_OUTPUT %04X\n", eeprom_dat);
|
||||
break;
|
||||
case EEPROM_OP_EW:
|
||||
pclog("EEPROM_OP_EW %i\n", eeprom_dat);
|
||||
switch (eeprom_dat)
|
||||
{
|
||||
case EEPROM_OP_EWDS:
|
||||
eeprom_wp = 1;
|
||||
break;
|
||||
case EEPROM_OP_WRAL:
|
||||
opcode = EEPROM_OP_WRALMAIN;
|
||||
eeprom_count = 20;
|
||||
break;
|
||||
case EEPROM_OP_ERAL:
|
||||
if (!eeprom_wp)
|
||||
{
|
||||
memset(eeprom, 0xff, 128);
|
||||
ati_eeprom_save();
|
||||
}
|
||||
break;
|
||||
case EEPROM_OP_EWEN:
|
||||
eeprom_wp = 0;
|
||||
break;
|
||||
}
|
||||
eeprom_state = EEPROM_IDLE;
|
||||
eeprom_out = 1;
|
||||
break;
|
||||
|
||||
case EEPROM_OP_ERASE:
|
||||
pclog("EEPROM_OP_ERASE %i\n", eeprom_dat);
|
||||
if (!eeprom_wp)
|
||||
{
|
||||
eeprom[eeprom_dat] = 0xffff;
|
||||
ati_eeprom_save();
|
||||
}
|
||||
eeprom_state = EEPROM_IDLE;
|
||||
eeprom_out = 1;
|
||||
break;
|
||||
|
||||
case EEPROM_OP_WRALMAIN:
|
||||
pclog("EEPROM_OP_WRAL %04X\n", eeprom_dat);
|
||||
if (!eeprom_wp)
|
||||
{
|
||||
for (c = 0; c < 256; c++)
|
||||
eeprom[c] = eeprom_dat;
|
||||
ati_eeprom_save();
|
||||
}
|
||||
eeprom_state = EEPROM_IDLE;
|
||||
eeprom_out = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
oldena = ena;
|
||||
}
|
||||
else if (!clk && oldclk)
|
||||
{
|
||||
if (ena)
|
||||
{
|
||||
switch (eeprom_state)
|
||||
{
|
||||
case EEPROM_OUTPUT:
|
||||
eeprom_out = (eeprom_dat & 0x10000) ? 1 : 0;
|
||||
eeprom_dat <<= 1;
|
||||
pclog("EEPROM_OUTPUT - data %i\n", eeprom_out);
|
||||
eeprom_count--;
|
||||
if (!eeprom_count)
|
||||
{
|
||||
pclog("EEPROM_OUTPUT complete\n");
|
||||
eeprom_state = EEPROM_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
oldclk = clk;
|
||||
}
|
||||
|
||||
int ati_eeprom_read()
|
||||
{
|
||||
return eeprom_out;
|
||||
}
|
||||
|
||||
3
src/vid_ati_eeprom.h
Normal file
3
src/vid_ati_eeprom.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
void ati_eeprom_load(char *fn, int type);
|
||||
void ati_eeprom_write(int ena, int clk, int dat);
|
||||
int ati_eeprom_read();
|
||||
1767
src/vid_ati_mach64.c
Normal file
1767
src/vid_ati_mach64.c
Normal file
File diff suppressed because it is too large
Load diff
850
src/vid_cl5429.c
Normal file
850
src/vid_cl5429.c
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
/*Cirrus Logic CL-GD5429 emulation*/
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "video.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_svga_render.h"
|
||||
#include "vid_unk_ramdac.h"
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t bank[2];
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t bg_col, fg_col;
|
||||
uint16_t width, height;
|
||||
uint16_t dst_pitch, src_pitch;
|
||||
uint32_t dst_addr, src_addr;
|
||||
uint8_t mask, mode, rop;
|
||||
|
||||
uint32_t dst_addr_backup, src_addr_backup;
|
||||
uint16_t width_backup, height_internal;
|
||||
int x_count;
|
||||
} blt;
|
||||
|
||||
} gd5429;
|
||||
|
||||
void gd5429_write(uint32_t addr, uint8_t val, void *priv);
|
||||
uint8_t gd5429_read(uint32_t addr, void *priv);
|
||||
|
||||
void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv);
|
||||
uint8_t gd5429_mmio_read(uint32_t addr, void *priv);
|
||||
|
||||
void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv);
|
||||
void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv);
|
||||
|
||||
void gd5429_recalc_banking();
|
||||
void gd5429_recalc_mapping();
|
||||
|
||||
void gd5429_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
pclog("gd5429 out %04X %02X\n", addr, val);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3c4:
|
||||
seqaddr = val;
|
||||
break;
|
||||
case 0x3c5:
|
||||
if (seqaddr > 5)
|
||||
{
|
||||
seqregs[seqaddr & 0x1f] = val;
|
||||
switch (seqaddr & 0x1f)
|
||||
{
|
||||
case 0x10: case 0x30: case 0x50: case 0x70:
|
||||
case 0x90: case 0xb0: case 0xd0: case 0xf0:
|
||||
svga_hwcursor.x = (val << 3) | ((seqaddr >> 5) & 7);
|
||||
pclog("svga_hwcursor.x = %i\n", svga_hwcursor.x);
|
||||
break;
|
||||
case 0x11: case 0x31: case 0x51: case 0x71:
|
||||
case 0x91: case 0xb1: case 0xd1: case 0xf1:
|
||||
svga_hwcursor.y = (val << 3) | ((seqaddr >> 5) & 7);
|
||||
pclog("svga_hwcursor.y = %i\n", svga_hwcursor.y);
|
||||
break;
|
||||
case 0x12:
|
||||
svga_hwcursor.ena = val & 1;
|
||||
pclog("svga_hwcursor.ena = %i\n", svga_hwcursor.ena);
|
||||
break;
|
||||
case 0x13:
|
||||
svga_hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256);
|
||||
pclog("svga_hwcursor.addr = %x\n", svga_hwcursor.addr);
|
||||
break;
|
||||
|
||||
case 0x17:
|
||||
gd5429_recalc_mapping();
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3cf:
|
||||
if (gdcaddr == 5)
|
||||
{
|
||||
gdcreg[5] = val;
|
||||
if (gdcreg[0xb] & 0x04)
|
||||
writemode = gdcreg[5] & 7;
|
||||
else
|
||||
writemode = gdcreg[5] & 3;
|
||||
readmode = val & 8;
|
||||
pclog("writemode = %i\n", writemode);
|
||||
return;
|
||||
}
|
||||
if (gdcaddr == 6)
|
||||
{
|
||||
if ((gdcreg[6] & 0xc) != (val & 0xc))
|
||||
{
|
||||
gdcreg[6] = val;
|
||||
gd5429_recalc_mapping();
|
||||
}
|
||||
gdcreg[6] = val;
|
||||
return;
|
||||
}
|
||||
if (gdcaddr > 8)
|
||||
{
|
||||
gdcreg[gdcaddr & 0x3f] = val;
|
||||
switch (gdcaddr)
|
||||
{
|
||||
case 0x09: case 0x0a: case 0x0b:
|
||||
gd5429_recalc_banking();
|
||||
if (gdcreg[0xb] & 0x04)
|
||||
writemode = gdcreg[5] & 7;
|
||||
else
|
||||
writemode = gdcreg[5] & 3;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
crtcreg = val & 0x3f;
|
||||
return;
|
||||
case 0x3D5:
|
||||
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
||||
old=crtc[crtcreg];
|
||||
crtc[crtcreg]=val;
|
||||
|
||||
if (old!=val)
|
||||
{
|
||||
if (crtcreg<0xE || crtcreg>0x10)
|
||||
{
|
||||
fullchange=changeframecount;
|
||||
svga_recalctimings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
svga_out(addr, val, NULL);
|
||||
}
|
||||
|
||||
uint8_t gd5429_in(uint16_t addr, void *priv)
|
||||
{
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3c5:
|
||||
if (seqaddr > 5)
|
||||
{
|
||||
switch (seqaddr)
|
||||
{
|
||||
case 6:
|
||||
return ((seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f;
|
||||
}
|
||||
return seqregs[seqaddr & 0x3f];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3cf:
|
||||
if (gdcaddr > 8)
|
||||
{
|
||||
return gdcreg[seqaddr & 0x3f];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
return crtcreg;
|
||||
case 0x3D5:
|
||||
switch (crtcreg)
|
||||
{
|
||||
case 0x27: /*ID*/
|
||||
return 0x9c; /*GD5429*/
|
||||
}
|
||||
return crtc[crtcreg];
|
||||
}
|
||||
return svga_in(addr, NULL);
|
||||
}
|
||||
|
||||
void gd5429_recalc_banking()
|
||||
{
|
||||
if (gdcreg[0xb] & 0x20)
|
||||
gd5429.bank[0] = (gdcreg[0x09] & 0x7f) << 14;
|
||||
else
|
||||
gd5429.bank[0] = gdcreg[0x09] << 12;
|
||||
|
||||
if (gdcreg[0xb] & 0x01)
|
||||
{
|
||||
if (gdcreg[0xb] & 0x20)
|
||||
gd5429.bank[1] = (gdcreg[0x0a] & 0x7f) << 14;
|
||||
else
|
||||
gd5429.bank[1] = gdcreg[0x0a] << 12;
|
||||
}
|
||||
else
|
||||
gd5429.bank[1] = gd5429.bank[0] + 0x8000;
|
||||
}
|
||||
|
||||
void gd5429_recalc_mapping()
|
||||
{
|
||||
mem_removehandler(0xa0000, 0x20000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
||||
mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
mem_removehandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL);
|
||||
pclog("Write mapping %02X %i\n", gdcreg[6], seqregs[0x17] & 0x04);
|
||||
switch (gdcreg[6] & 0x0C)
|
||||
{
|
||||
case 0x0: /*128k at A0000*/
|
||||
mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
||||
break;
|
||||
case 0x4: /*64k at A0000*/
|
||||
mem_sethandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
||||
if (seqregs[0x17] & 0x04)
|
||||
mem_sethandler(0xb8000, 0x00100, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL);
|
||||
break;
|
||||
case 0x8: /*32k at B0000*/
|
||||
mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
case 0xC: /*32k at B8000*/
|
||||
mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gd5429_recalctimings()
|
||||
{
|
||||
if (seqregs[7] & 0x01)
|
||||
{
|
||||
svga_render = svga_render_8bpp_highres;
|
||||
}
|
||||
|
||||
svga_ma |= ((crtc[0x1b] & 0x01) << 16) | ((crtc[0x1b] & 0xc) << 15);
|
||||
pclog("MA now %05X %02X\n", svga_ma, crtc[0x1b]);
|
||||
}
|
||||
|
||||
void gd5429_hwcursor_draw(int displine)
|
||||
{
|
||||
int x;
|
||||
uint8_t dat[2];
|
||||
int xx;
|
||||
int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff;
|
||||
|
||||
pclog("HWcursor %i %i %i %i %x %02X %02X\n", svga_hwcursor_latch.x, svga_hwcursor_latch.y, offset, displine, svga_hwcursor_latch.addr, vram[svga_hwcursor_latch.addr], vram[svga_hwcursor_latch.addr + 0x80]);
|
||||
for (x = 0; x < 32; x += 8)
|
||||
{
|
||||
dat[0] = vram[svga_hwcursor_latch.addr];
|
||||
dat[1] = vram[svga_hwcursor_latch.addr + 0x80];
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
{
|
||||
if (offset >= svga_hwcursor_latch.x)
|
||||
{
|
||||
if (dat[1] & 0x80)
|
||||
((uint32_t *)buffer32->line[displine])[offset + 32] = 0;
|
||||
if (dat[0] & 0x80)
|
||||
((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
|
||||
}
|
||||
|
||||
offset++;
|
||||
dat[0] <<= 1;
|
||||
dat[1] <<= 1;
|
||||
}
|
||||
svga_hwcursor_latch.addr++;
|
||||
}
|
||||
}
|
||||
|
||||
int gd5429_init()
|
||||
{
|
||||
svga_recalctimings_ex = gd5429_recalctimings;
|
||||
svga_hwcursor_draw = gd5429_hwcursor_draw;
|
||||
svga_vram_limit = 2 << 20; /*2mb*/
|
||||
vrammask = 0x1fffff;
|
||||
|
||||
svga_hwcursor.yoff = 32;
|
||||
svga_hwcursor.xoff = 0;
|
||||
|
||||
memset(&gd5429, 0, sizeof(gd5429));
|
||||
|
||||
gd5429.bank[1] = 0x8000;
|
||||
|
||||
return svga_init();
|
||||
}
|
||||
|
||||
static uint8_t la, lb, lc, ld;
|
||||
|
||||
uint8_t gd5429_read_linear(uint32_t addr, void *priv);
|
||||
void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv);
|
||||
|
||||
void gd5429_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
// pclog("gd5429_write : %05X %02X ", addr, val);
|
||||
addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1];
|
||||
// pclog("%08X\n", addr);
|
||||
gd5429_write_linear(addr, val, priv);
|
||||
}
|
||||
|
||||
uint8_t gd5429_read(uint32_t addr, void *priv)
|
||||
{
|
||||
uint8_t ret;
|
||||
// pclog("gd5429_read : %05X ", addr);
|
||||
addr = (addr & 0x7fff) + gd5429.bank[(addr >> 15) & 1];
|
||||
ret = gd5429_read_linear(addr, priv);
|
||||
// pclog("%08X %02X\n", addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gd5429_write_linear(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t vala,valb,valc,vald,wm=writemask;
|
||||
int writemask2 = writemask;
|
||||
|
||||
cycles -= video_timing_b;
|
||||
cycles_lost += video_timing_b;
|
||||
|
||||
egawrites++;
|
||||
|
||||
// if (svga_output) pclog("Write LFB %08X %02X ", addr, val);
|
||||
if (!(gdcreg[6]&1)) fullchange=2;
|
||||
if (chain4 && (writemode < 4))
|
||||
{
|
||||
writemask2=1<<(addr&3);
|
||||
addr&=~3;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr<<=2;
|
||||
}
|
||||
addr &= 0x7fffff;
|
||||
// if (svga_output) pclog("%08X\n", addr);
|
||||
changedvram[addr>>10]=changeframecount;
|
||||
|
||||
switch (writemode)
|
||||
{
|
||||
case 4:
|
||||
pclog("Writemode 4 : %X ", addr);
|
||||
addr <<= 1;
|
||||
changedvram[addr>>10]=changeframecount;
|
||||
pclog("%X %X\n", addr, val);
|
||||
if (val & 0x80)
|
||||
vram[addr + 0] = gdcreg[1];
|
||||
if (val & 0x40)
|
||||
vram[addr + 1] = gdcreg[1];
|
||||
if (val & 0x20)
|
||||
vram[addr + 2] = gdcreg[1];
|
||||
if (val & 0x10)
|
||||
vram[addr + 3] = gdcreg[1];
|
||||
if (val & 0x08)
|
||||
vram[addr + 4] = gdcreg[1];
|
||||
if (val & 0x04)
|
||||
vram[addr + 5] = gdcreg[1];
|
||||
if (val & 0x02)
|
||||
vram[addr + 6] = gdcreg[1];
|
||||
if (val & 0x01)
|
||||
vram[addr + 7] = gdcreg[1];
|
||||
break;
|
||||
|
||||
case 5:
|
||||
pclog("Writemode 5 : %X ", addr);
|
||||
addr <<= 1;
|
||||
changedvram[addr>>10]=changeframecount;
|
||||
pclog("%X %X\n", addr, val);
|
||||
vram[addr + 0] = (val & 0x80) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 1] = (val & 0x40) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 2] = (val & 0x20) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 3] = (val & 0x10) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 4] = (val & 0x08) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 5] = (val & 0x04) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 6] = (val & 0x02) ? gdcreg[1] : gdcreg[0];
|
||||
vram[addr + 7] = (val & 0x01) ? gdcreg[1] : gdcreg[0];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (writemask2&1) vram[addr]=la;
|
||||
if (writemask2&2) vram[addr|0x1]=lb;
|
||||
if (writemask2&4) vram[addr|0x2]=lc;
|
||||
if (writemask2&8) vram[addr|0x3]=ld;
|
||||
break;
|
||||
case 0:
|
||||
if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val];
|
||||
if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1])
|
||||
{
|
||||
if (writemask2&1) vram[addr]=val;
|
||||
if (writemask2&2) vram[addr|0x1]=val;
|
||||
if (writemask2&4) vram[addr|0x2]=val;
|
||||
if (writemask2&8) vram[addr|0x3]=val;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0;
|
||||
else vala=val;
|
||||
if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0;
|
||||
else valb=val;
|
||||
if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0;
|
||||
else valc=val;
|
||||
if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0;
|
||||
else vald=val;
|
||||
|
||||
switch (gdcreg[3]&0x18)
|
||||
{
|
||||
case 0: /*Set*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
||||
break;
|
||||
case 8: /*AND*/
|
||||
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
||||
break;
|
||||
case 0x10: /*OR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
||||
break;
|
||||
case 0x18: /*XOR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
||||
break;
|
||||
}
|
||||
// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!(gdcreg[3]&0x18) && !gdcreg[1])
|
||||
{
|
||||
if (writemask2&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]);
|
||||
if (writemask2&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]);
|
||||
if (writemask2&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]);
|
||||
if (writemask2&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]);
|
||||
}
|
||||
else
|
||||
{
|
||||
vala=((val&1)?0xFF:0);
|
||||
valb=((val&2)?0xFF:0);
|
||||
valc=((val&4)?0xFF:0);
|
||||
vald=((val&8)?0xFF:0);
|
||||
switch (gdcreg[3]&0x18)
|
||||
{
|
||||
case 0: /*Set*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
||||
break;
|
||||
case 8: /*AND*/
|
||||
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
||||
break;
|
||||
case 0x10: /*OR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
||||
break;
|
||||
case 0x18: /*XOR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val];
|
||||
wm=gdcreg[8];
|
||||
gdcreg[8]&=val;
|
||||
|
||||
vala=(gdcreg[0]&1)?0xFF:0;
|
||||
valb=(gdcreg[0]&2)?0xFF:0;
|
||||
valc=(gdcreg[0]&4)?0xFF:0;
|
||||
vald=(gdcreg[0]&8)?0xFF:0;
|
||||
switch (gdcreg[3]&0x18)
|
||||
{
|
||||
case 0: /*Set*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]);
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]);
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]);
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]);
|
||||
break;
|
||||
case 8: /*AND*/
|
||||
if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld;
|
||||
break;
|
||||
case 0x10: /*OR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld;
|
||||
break;
|
||||
case 0x18: /*XOR*/
|
||||
if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la;
|
||||
if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb;
|
||||
if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc;
|
||||
if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld;
|
||||
break;
|
||||
}
|
||||
gdcreg[8]=wm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t gd5429_read_linear(uint32_t addr, void *priv)
|
||||
{
|
||||
uint8_t temp,temp2,temp3,temp4;
|
||||
|
||||
cycles -= video_timing_b;
|
||||
cycles_lost += video_timing_b;
|
||||
|
||||
egareads++;
|
||||
|
||||
if (chain4)
|
||||
{
|
||||
addr &= 0x7fffff;
|
||||
if (addr >= svga_vram_limit)
|
||||
return 0xff;
|
||||
return vram[addr & 0x7fffff];
|
||||
}
|
||||
else addr<<=2;
|
||||
|
||||
addr &= 0x7fffff;
|
||||
|
||||
if (addr >= svga_vram_limit)
|
||||
return 0xff;
|
||||
|
||||
la=vram[addr];
|
||||
lb=vram[addr|0x1];
|
||||
lc=vram[addr|0x2];
|
||||
ld=vram[addr|0x3];
|
||||
if (readmode)
|
||||
{
|
||||
temp= (colournocare&1) ?0xFF:0;
|
||||
temp&=la;
|
||||
temp^=(colourcompare&1)?0xFF:0;
|
||||
temp2= (colournocare&2) ?0xFF:0;
|
||||
temp2&=lb;
|
||||
temp2^=(colourcompare&2)?0xFF:0;
|
||||
temp3= (colournocare&4) ?0xFF:0;
|
||||
temp3&=lc;
|
||||
temp3^=(colourcompare&4)?0xFF:0;
|
||||
temp4= (colournocare&8) ?0xFF:0;
|
||||
temp4&=ld;
|
||||
temp4^=(colourcompare&8)?0xFF:0;
|
||||
return ~(temp|temp2|temp3|temp4);
|
||||
}
|
||||
//printf("Read %02X %04X %04X\n",vram[addr|readplane],addr,readplane);
|
||||
return vram[addr|readplane];
|
||||
}
|
||||
|
||||
void gd5429_start_blit(uint32_t cpu_dat, int count)
|
||||
{
|
||||
pclog("gd5429_start_blit %i\n", count);
|
||||
if (count == -1)
|
||||
{
|
||||
gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr;
|
||||
gd5429.blt.src_addr_backup = gd5429.blt.src_addr;
|
||||
gd5429.blt.width_backup = gd5429.blt.width;
|
||||
gd5429.blt.height_internal = gd5429.blt.height;
|
||||
gd5429.blt.x_count = gd5429.blt.mask & 7;
|
||||
pclog("gd5429_start_blit : size %i, %i\n", gd5429.blt.width, gd5429.blt.height);
|
||||
|
||||
if (gd5429.blt.mode & 0x04)
|
||||
{
|
||||
// pclog("blt.mode & 0x04\n");
|
||||
mem_removehandler(0xa0000, 0x10000, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL, NULL);
|
||||
mem_sethandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
||||
gd5429_recalc_mapping();
|
||||
}
|
||||
}
|
||||
|
||||
while (count)
|
||||
{
|
||||
uint8_t src, dst;
|
||||
int mask;
|
||||
|
||||
if (gd5429.blt.mode & 0x04)
|
||||
{
|
||||
if (gd5429.blt.mode & 0x80)
|
||||
{
|
||||
src = (cpu_dat & 0x80) ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
||||
mask = cpu_dat & 0x80;
|
||||
cpu_dat <<= 1;
|
||||
count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = cpu_dat & 0xff;
|
||||
cpu_dat >>= 8;
|
||||
count -= 8;
|
||||
mask = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gd5429.blt.mode & 0xc0)
|
||||
{
|
||||
case 0x00:
|
||||
src = vram[gd5429.blt.src_addr & vrammask];
|
||||
gd5429.blt.src_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1);
|
||||
mask = 1;
|
||||
break;
|
||||
case 0x40:
|
||||
src = vram[(gd5429.blt.src_addr & (vrammask & ~7)) | (gd5429.blt.dst_addr & 7)];
|
||||
mask = 1;
|
||||
break;
|
||||
case 0x80:
|
||||
mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> gd5429.blt.x_count);
|
||||
src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
||||
gd5429.blt.x_count++;
|
||||
if (gd5429.blt.x_count == 8)
|
||||
{
|
||||
gd5429.blt.x_count = 0;
|
||||
gd5429.blt.src_addr++;
|
||||
}
|
||||
break;
|
||||
case 0xc0:
|
||||
mask = vram[gd5429.blt.src_addr & vrammask] & (0x80 >> (gd5429.blt.dst_addr & 7));
|
||||
src = mask ? gd5429.blt.fg_col : gd5429.blt.bg_col;
|
||||
break;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
dst = vram[gd5429.blt.dst_addr & vrammask];
|
||||
changedvram[(gd5429.blt.dst_addr & vrammask) >> 10] = changeframecount;
|
||||
|
||||
pclog("Blit %i,%i %06X %06X %06X %02X %02X %02X %02X ", gd5429.blt.width, gd5429.blt.height_internal, gd5429.blt.src_addr, gd5429.blt.dst_addr, gd5429.blt.src_addr & vrammask, vram[gd5429.blt.src_addr & vrammask], 0x80 >> (gd5429.blt.dst_addr & 7), src, dst);
|
||||
switch (gd5429.blt.rop)
|
||||
{
|
||||
case 0x00: dst = 0; break;
|
||||
case 0x05: dst = src & dst; break;
|
||||
case 0x06: dst = dst; break;
|
||||
case 0x09: dst = src & ~dst; break;
|
||||
case 0x0b: dst = ~ dst; break;
|
||||
case 0x0d: dst = src; break;
|
||||
case 0x0e: dst = 0xff; break;
|
||||
case 0x50: dst = ~ src & dst; break;
|
||||
case 0x59: dst = src ^ dst; break;
|
||||
case 0x6d: dst = src | dst; break;
|
||||
case 0x90: dst = ~(src | dst); break;
|
||||
case 0x95: dst = ~(src ^ dst); break;
|
||||
case 0xad: dst = src | ~dst; break;
|
||||
case 0xd0: dst = ~src; break;
|
||||
case 0xd6: dst = ~src | dst; break;
|
||||
case 0xda: dst = ~(src & dst); break;
|
||||
}
|
||||
pclog("%02X %02X\n", dst, mask);
|
||||
|
||||
if ((gd5429.blt.width_backup - gd5429.blt.width) >= (gd5429.blt.mask & 7) &&
|
||||
!((gd5429.blt.mode & 0x08) && !mask))
|
||||
vram[gd5429.blt.dst_addr & vrammask] = dst;
|
||||
|
||||
gd5429.blt.dst_addr += ((gd5429.blt.mode & 0x01) ? -1 : 1);
|
||||
|
||||
gd5429.blt.width--;
|
||||
|
||||
if (gd5429.blt.width == 0xffff)
|
||||
{
|
||||
gd5429.blt.width = gd5429.blt.width_backup;
|
||||
|
||||
gd5429.blt.dst_addr = gd5429.blt.dst_addr_backup = gd5429.blt.dst_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.dst_pitch : gd5429.blt.dst_pitch);
|
||||
|
||||
switch (gd5429.blt.mode & 0xc0)
|
||||
{
|
||||
case 0x00:
|
||||
gd5429.blt.src_addr = gd5429.blt.src_addr_backup = gd5429.blt.src_addr_backup + ((gd5429.blt.mode & 0x01) ? -gd5429.blt.src_pitch : gd5429.blt.src_pitch);
|
||||
break;
|
||||
case 0x40:
|
||||
gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -8 : 8)) & 0x38) | (gd5429.blt.src_addr & ~0x38);
|
||||
break;
|
||||
case 0x80:
|
||||
if (gd5429.blt.x_count != 0)
|
||||
{
|
||||
gd5429.blt.x_count = 0;
|
||||
gd5429.blt.src_addr++;
|
||||
}
|
||||
break;
|
||||
case 0xc0:
|
||||
gd5429.blt.src_addr = ((gd5429.blt.src_addr + ((gd5429.blt.mode & 0x01) ? -1 : 1)) & 7) | (gd5429.blt.src_addr & ~7);
|
||||
break;
|
||||
}
|
||||
|
||||
gd5429.blt.height_internal--;
|
||||
if (gd5429.blt.height_internal == 0xffff)
|
||||
{
|
||||
if (gd5429.blt.mode & 0x04)
|
||||
{
|
||||
mem_removehandler(0xa0000, 0x10000, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l, NULL);
|
||||
gd5429_recalc_mapping();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gd5429.blt.mode & 0x04)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gd5429_mmio_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
pclog("MMIO write %08X %02X\n", addr, val);
|
||||
switch (addr & 0xff)
|
||||
{
|
||||
case 0x00:
|
||||
gd5429.blt.bg_col = (gd5429.blt.bg_col & 0xff00) | val;
|
||||
break;
|
||||
case 0x01:
|
||||
gd5429.blt.bg_col = (gd5429.blt.bg_col & 0x00ff) | (val << 8);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
gd5429.blt.fg_col = (gd5429.blt.fg_col & 0xff00) | val;
|
||||
break;
|
||||
case 0x05:
|
||||
gd5429.blt.fg_col = (gd5429.blt.fg_col & 0x00ff) | (val << 8);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
gd5429.blt.width = (gd5429.blt.width & 0xff00) | val;
|
||||
break;
|
||||
case 0x09:
|
||||
gd5429.blt.width = (gd5429.blt.width & 0x00ff) | (val << 8);
|
||||
break;
|
||||
case 0x0a:
|
||||
gd5429.blt.height = (gd5429.blt.height & 0xff00) | val;
|
||||
break;
|
||||
case 0x0b:
|
||||
gd5429.blt.height = (gd5429.blt.height & 0x00ff) | (val << 8);
|
||||
break;
|
||||
case 0x0c:
|
||||
gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0xff00) | val;
|
||||
break;
|
||||
case 0x0d:
|
||||
gd5429.blt.dst_pitch = (gd5429.blt.dst_pitch & 0x00ff) | (val << 8);
|
||||
break;
|
||||
case 0x0e:
|
||||
gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0xff00) | val;
|
||||
break;
|
||||
case 0x0f:
|
||||
gd5429.blt.src_pitch = (gd5429.blt.src_pitch & 0x00ff) | (val << 8);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xffff00) | val;
|
||||
break;
|
||||
case 0x11:
|
||||
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0xff00ff) | (val << 8);
|
||||
break;
|
||||
case 0x12:
|
||||
gd5429.blt.dst_addr = (gd5429.blt.dst_addr & 0x00ffff) | (val << 16);
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xffff00) | val;
|
||||
break;
|
||||
case 0x15:
|
||||
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0xff00ff) | (val << 8);
|
||||
break;
|
||||
case 0x16:
|
||||
gd5429.blt.src_addr = (gd5429.blt.src_addr & 0x00ffff) | (val << 16);
|
||||
break;
|
||||
|
||||
case 0x17:
|
||||
gd5429.blt.mask = val;
|
||||
break;
|
||||
case 0x18:
|
||||
gd5429.blt.mode = val;
|
||||
break;
|
||||
|
||||
case 0x1a:
|
||||
gd5429.blt.rop = val;
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
if (val & 0x02)
|
||||
gd5429_start_blit(0, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t gd5429_mmio_read(uint32_t addr, void *priv)
|
||||
{
|
||||
pclog("MMIO read %08X\n", addr);
|
||||
switch (addr & 0xff)
|
||||
{
|
||||
case 0x40: /*BLT status*/
|
||||
return 0;
|
||||
}
|
||||
return 0xff; /*All other registers read-only*/
|
||||
}
|
||||
|
||||
void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
pclog("gd5429_blt_write_w %08X %08X\n", addr, val);
|
||||
gd5429_start_blit(val, 16);
|
||||
}
|
||||
|
||||
void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
pclog("gd5429_blt_write_l %08X %08X %04X %04X\n", addr, val, ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00));
|
||||
if ((gd5429.blt.mode & 0x84) == 0x84)
|
||||
{
|
||||
gd5429_start_blit( val & 0xff, 8);
|
||||
gd5429_start_blit((val >> 8) & 0xff, 8);
|
||||
gd5429_start_blit((val >> 16) & 0xff, 8);
|
||||
gd5429_start_blit((val >> 24) & 0xff, 8);
|
||||
}
|
||||
else
|
||||
gd5429_start_blit(val, 32);
|
||||
}
|
||||
|
||||
GFXCARD vid_gd5429 =
|
||||
{
|
||||
gd5429_init,
|
||||
/*IO at 3Cx/3Dx*/
|
||||
gd5429_out,
|
||||
gd5429_in,
|
||||
/*IO at 3Ax/3Bx*/
|
||||
video_out_null,
|
||||
video_in_null,
|
||||
|
||||
svga_poll,
|
||||
svga_recalctimings,
|
||||
|
||||
svga_write,
|
||||
video_write_null,
|
||||
video_write_null,
|
||||
|
||||
svga_read,
|
||||
video_read_null,
|
||||
video_read_null
|
||||
};
|
||||
0
src/vid_et4000w32.h
Normal file
0
src/vid_et4000w32.h
Normal file
63
src/vid_ics2595.c
Normal file
63
src/vid_ics2595.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*ICS2595 clock chip emulation
|
||||
Used by ATI Mach64*/
|
||||
|
||||
#include "ibm.h"
|
||||
#include "vid_ics2595.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ICS2595_IDLE,
|
||||
ICS2595_WRITE,
|
||||
ICS2595_READ
|
||||
};
|
||||
|
||||
static int ics2595_oldfs3, ics2595_oldfs2;
|
||||
static int ics2595_dat;
|
||||
static int ics2595_pos;
|
||||
static int ics2595_state = ICS2595_IDLE;
|
||||
|
||||
static int ics2595_div[4] = {8, 4, 2, 1};
|
||||
|
||||
static double ics2595_clocks[16];
|
||||
double ics2595_output_clock;
|
||||
|
||||
void ics2595_write(int strobe, int dat)
|
||||
{
|
||||
pclog("ics2595_write : %i %i\n", strobe, dat);
|
||||
if (strobe)
|
||||
{
|
||||
if ((dat & 8) && !ics2595_oldfs3) /*Data clock*/
|
||||
{
|
||||
pclog(" - new dat %i\n", dat & 4);
|
||||
switch (ics2595_state)
|
||||
{
|
||||
case ICS2595_IDLE:
|
||||
ics2595_state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE;
|
||||
ics2595_pos = 0;
|
||||
break;
|
||||
case ICS2595_WRITE:
|
||||
ics2595_dat = (ics2595_dat >> 1);
|
||||
if (dat & 4)
|
||||
ics2595_dat |= (1 << 19);
|
||||
ics2595_pos++;
|
||||
if (ics2595_pos == 20)
|
||||
{
|
||||
int d, n, l;
|
||||
pclog("ICS2595_WRITE : dat %08X\n", ics2595_dat);
|
||||
l = (ics2595_dat >> 2) & 31;
|
||||
n = ((ics2595_dat >> 7) & 255) + 257;
|
||||
d = ics2595_div[(ics2595_dat >> 16) & 3];
|
||||
|
||||
ics2595_clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d;
|
||||
pclog("ICS2595 clock set - L %i N %i D %i freq = %f\n", l, n, d, (14318181.8 * ((double)n / 46.0)) / (double)d);
|
||||
ics2595_state = ICS2595_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ics2595_oldfs2 = dat & 4;
|
||||
ics2595_oldfs3 = dat & 8;
|
||||
}
|
||||
ics2595_output_clock = ics2595_clocks[dat];
|
||||
}
|
||||
2
src/vid_ics2595.h
Normal file
2
src/vid_ics2595.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
void ics2595_write(int strobe, int dat);
|
||||
extern double ics2595_output_clock;
|
||||
467
src/vid_s3_virge.c
Normal file
467
src/vid_s3_virge.c
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
/*S3 ViRGE emulation
|
||||
|
||||
The SVGA core is largely the same as older S3 chips, but the blitter is totally different*/
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "pci.h"
|
||||
#include "video.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_svga_render.h"
|
||||
//#include "vid_sdac_ramdac.h"
|
||||
|
||||
void s3_virge_updatemapping();
|
||||
|
||||
static uint8_t s3_bank;
|
||||
static uint8_t s3_ma_ext;
|
||||
static int s3_width = 1024;
|
||||
static int s3_bpp = 0;
|
||||
|
||||
static uint8_t s3_virge_id, s3_virge_id_high, s3_virge_id_low, s3_virge_rev;
|
||||
|
||||
uint8_t s3_virge_mmio_read(uint32_t addr, void *priv);
|
||||
uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv);
|
||||
uint32_t s3_virge_mmio_read_l(uint32_t addr, void *priv);
|
||||
void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv);
|
||||
void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv);
|
||||
void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv);
|
||||
|
||||
void s3_virge_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3c5:
|
||||
if (seqaddr >= 0x10)
|
||||
{
|
||||
seqregs[seqaddr&0x1F]=val;
|
||||
return;
|
||||
}
|
||||
if (seqaddr == 4) /*Chain-4 - update banking*/
|
||||
{
|
||||
if (val & 8) svgawbank = svgarbank = s3_bank << 16;
|
||||
else svgawbank = svgarbank = s3_bank << 14;
|
||||
}
|
||||
break;
|
||||
|
||||
//case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
|
||||
// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
|
||||
//sdac_ramdac_out(addr,val);
|
||||
//return;
|
||||
|
||||
case 0x3D4:
|
||||
crtcreg=val&0x7f;
|
||||
return;
|
||||
case 0x3D5:
|
||||
// if (crtcreg == 0x67) pclog("Write CRTC R%02X %02X\n", crtcreg, val);
|
||||
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
||||
if (crtcreg >= 0x20 && crtcreg != 0x38 && (crtc[0x38] & 0xcc) != 0x48) return;
|
||||
old=crtc[crtcreg];
|
||||
crtc[crtcreg]=val;
|
||||
switch (crtcreg)
|
||||
{
|
||||
case 0x31:
|
||||
s3_ma_ext = (s3_ma_ext & 0x1c) | ((val & 0x30) >> 4);
|
||||
vrammask = (val & 8) ? 0x3fffff : 0x3ffff;
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
switch (crtc[0x50] & 0xc1)
|
||||
{
|
||||
case 0x00: s3_width = (crtc[0x31] & 2) ? 2048 : 1024; break;
|
||||
case 0x01: s3_width = 1152; break;
|
||||
case 0x40: s3_width = 640; break;
|
||||
case 0x80: s3_width = 800; break;
|
||||
case 0x81: s3_width = 1600; break;
|
||||
case 0xc0: s3_width = 1280; break;
|
||||
}
|
||||
s3_bpp = (crtc[0x50] >> 4) & 3;
|
||||
break;
|
||||
case 0x69:
|
||||
s3_ma_ext = val & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x35:
|
||||
s3_bank = (s3_bank & 0x70) | (val & 0xf);
|
||||
// pclog("CRTC write R35 %02X\n", val);
|
||||
if (chain4) svgawbank = svgarbank = s3_bank << 16;
|
||||
else svgawbank = svgarbank = s3_bank << 14;
|
||||
break;
|
||||
case 0x51:
|
||||
s3_bank = (s3_bank & 0x4f) | ((val & 0xc) << 2);
|
||||
if (chain4) svgawbank = svgarbank = s3_bank << 16;
|
||||
else svgawbank = svgarbank = s3_bank << 14;
|
||||
s3_ma_ext = (s3_ma_ext & ~0xc) | ((val & 3) << 2);
|
||||
break;
|
||||
case 0x6a:
|
||||
s3_bank = val;
|
||||
// pclog("CRTC write R6a %02X\n", val);
|
||||
if (chain4) svgawbank = svgarbank = s3_bank << 16;
|
||||
else svgawbank = svgarbank = s3_bank << 14;
|
||||
break;
|
||||
|
||||
case 0x3a:
|
||||
if (val & 0x10) gdcreg[5] |= 0x40; /*Horrible cheat*/
|
||||
break;
|
||||
|
||||
case 0x45:
|
||||
svga_hwcursor.ena = val & 1;
|
||||
break;
|
||||
case 0x48:
|
||||
svga_hwcursor.x = ((crtc[0x46] << 8) | crtc[0x47]) & 0x7ff;
|
||||
if (bpp == 32) svga_hwcursor.x >>= 1;
|
||||
svga_hwcursor.y = ((crtc[0x48] << 8) | crtc[0x49]) & 0x7ff;
|
||||
svga_hwcursor.xoff = crtc[0x4e] & 63;
|
||||
svga_hwcursor.yoff = crtc[0x4f] & 63;
|
||||
svga_hwcursor.addr = ((((crtc[0x4c] << 8) | crtc[0x4d]) & 0xfff) * 1024) + (svga_hwcursor.yoff * 16);
|
||||
break;
|
||||
|
||||
case 0x53:
|
||||
case 0x58: case 0x59: case 0x5a:
|
||||
s3_virge_updatemapping();
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
switch (val >> 4)
|
||||
{
|
||||
case 3: bpp = 15; break;
|
||||
case 5: bpp = 16; break;
|
||||
case 7: bpp = 24; break;
|
||||
case 13: bpp = 32; break;
|
||||
default: bpp = 8; break;
|
||||
}
|
||||
break;
|
||||
//case 0x55: case 0x43:
|
||||
// pclog("Write CRTC R%02X %02X\n", crtcreg, val);
|
||||
}
|
||||
if (old!=val)
|
||||
{
|
||||
if (crtcreg<0xE || crtcreg>0x10)
|
||||
{
|
||||
fullchange=changeframecount;
|
||||
svga_recalctimings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
svga_out(addr, val, NULL);
|
||||
}
|
||||
|
||||
uint8_t s3_virge_in(uint16_t addr, void *priv)
|
||||
{
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
if (addr != 0x3da) pclog("S3 in %04X %04X:%08X\n", addr, CS, pc);
|
||||
switch (addr)
|
||||
{
|
||||
//case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
|
||||
// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc);
|
||||
//return sdac_ramdac_in(addr);
|
||||
|
||||
case 0x3c5:
|
||||
if (seqaddr >= 0x10)
|
||||
return seqregs[seqaddr&0x1F];
|
||||
break;
|
||||
|
||||
case 0x3D4:
|
||||
return crtcreg;
|
||||
case 0x3D5:
|
||||
// pclog("Read CRTC R%02X %04X:%04X\n", crtcreg, CS, pc);
|
||||
switch (crtcreg)
|
||||
{
|
||||
case 0x2d: return s3_virge_id_high; /*Extended chip ID*/
|
||||
case 0x2e: return s3_virge_id_low; /*New chip ID*/
|
||||
case 0x2f: return s3_virge_rev;
|
||||
case 0x30: return s3_virge_id; /*Chip ID*/
|
||||
case 0x31: return (crtc[0x31] & 0xcf) | ((s3_ma_ext & 3) << 4);
|
||||
case 0x35: return (crtc[0x35] & 0xf0) | (s3_bank & 0xf);
|
||||
case 0x51: return (crtc[0x51] & 0xf0) | ((s3_bank >> 2) & 0xc) | ((s3_ma_ext >> 2) & 3);
|
||||
case 0x69: return s3_ma_ext;
|
||||
case 0x6a: return s3_bank;
|
||||
}
|
||||
return crtc[crtcreg];
|
||||
}
|
||||
return svga_in(addr, NULL);
|
||||
}
|
||||
|
||||
void s3_virge_recalctimings()
|
||||
{
|
||||
// pclog("recalctimings\n");
|
||||
svga_ma |= (s3_ma_ext << 16);
|
||||
// pclog("SVGA_MA %08X\n", svga_ma);
|
||||
// if (gdcreg[5] & 0x40) svga_lowres = !(crtc[0x3a] & 0x10);
|
||||
if ((gdcreg[5] & 0x40) && (crtc[0x3a] & 0x10))
|
||||
{
|
||||
switch (bpp)
|
||||
{
|
||||
case 8:
|
||||
svga_render = svga_render_8bpp_highres;
|
||||
break;
|
||||
case 15:
|
||||
svga_render = svga_render_15bpp_highres;
|
||||
break;
|
||||
case 16:
|
||||
svga_render = svga_render_16bpp_highres;
|
||||
break;
|
||||
case 24:
|
||||
svga_render = svga_render_24bpp_highres;
|
||||
break;
|
||||
case 32:
|
||||
svga_render = svga_render_32bpp_highres;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (crtc[0x5d] & 0x01) svga_htotal += 0x100;
|
||||
if (crtc[0x5d] & 0x02) svga_hdisp += 0x100;
|
||||
if (crtc[0x5e] & 0x01) svga_vtotal += 0x400;
|
||||
if (crtc[0x5e] & 0x02) svga_dispend += 0x400;
|
||||
if (crtc[0x5e] & 0x10) svga_vsyncstart += 0x400;
|
||||
if (crtc[0x5e] & 0x40) svga_split += 0x400;
|
||||
if (crtc[0x51] & 0x30) svga_rowoffset += (crtc[0x51] & 0x30) << 4;
|
||||
else if (crtc[0x43] & 0x04) svga_rowoffset += 0x100;
|
||||
if (!svga_rowoffset) svga_rowoffset = 256;
|
||||
svga_interlace = crtc[0x42] & 0x20;
|
||||
if (bpp == 32)
|
||||
{
|
||||
svga_htotal <<= 2;
|
||||
svga_hdisp <<= 2;
|
||||
}
|
||||
//svga_clock = cpuclock / sdac_getclock((svga_miscout >> 2) & 3);
|
||||
// pclog("SVGA_CLOCK = %f %02X %f\n", svga_clock, svga_miscout, cpuclock);
|
||||
//if (bpp > 8) svga_clock /= 2;
|
||||
}
|
||||
|
||||
static uint32_t s3_linear_base = 0, s3_linear_size = 0;
|
||||
void s3_virge_updatemapping()
|
||||
{
|
||||
mem_removehandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL);
|
||||
|
||||
// video_write_a000_w = video_write_a000_l = NULL;
|
||||
|
||||
mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
mem_removehandler(0xa0000, 0x20000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL);
|
||||
pclog("Update mapping - bank %02X ", gdcreg[6] & 0xc);
|
||||
switch (gdcreg[6] & 0xc) /*Banked framebuffer*/
|
||||
{
|
||||
case 0x0: /*128k at A0000*/
|
||||
mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
case 0x4: /*64k at A0000*/
|
||||
mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
case 0x8: /*32k at B0000*/
|
||||
mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
case 0xC: /*32k at B8000*/
|
||||
mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
pclog("Linear framebuffer %02X ", crtc[0x58] & 0x10);
|
||||
if (crtc[0x58] & 0x10) /*Linear framebuffer*/
|
||||
{
|
||||
s3_linear_base = (crtc[0x5a] << 16) | (crtc[0x59] << 24);
|
||||
switch (crtc[0x58] & 3)
|
||||
{
|
||||
case 0: /*64k*/
|
||||
s3_linear_size = 0x10000;
|
||||
break;
|
||||
case 1: /*1mb*/
|
||||
s3_linear_size = 0x100000;
|
||||
break;
|
||||
case 2: /*2mb*/
|
||||
s3_linear_size = 0x200000;
|
||||
break;
|
||||
case 3: /*8mb*/
|
||||
s3_linear_size = 0x400000;
|
||||
break;
|
||||
}
|
||||
s3_linear_base &= ~(s3_linear_size - 1);
|
||||
// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]);
|
||||
pclog("Linear framebuffer at %08X size %08X\n", s3_linear_base, s3_linear_size);
|
||||
if (s3_linear_base == 0xa0000)
|
||||
mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL);
|
||||
else
|
||||
mem_sethandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL);
|
||||
}
|
||||
|
||||
pclog("Memory mapped IO %02X\n", crtc[0x53] & 0x18);
|
||||
output = 0;
|
||||
if ((crtc[0x53] & 0x18) == 0x10) /*Memory mapped IO*/
|
||||
{
|
||||
output = 3;
|
||||
if (crtc[0x53] & 0x20)
|
||||
mem_sethandler(0xb8000, 0x8000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL);
|
||||
else
|
||||
mem_sethandler(0xa8000, 0x8000, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, s3_virge_mmio_write, s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint8_t s3_virge_mmio_read(uint32_t addr, void *priv)
|
||||
{
|
||||
pclog("MMIO readb %08X\n", addr);
|
||||
return 0xff;
|
||||
}
|
||||
uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv)
|
||||
{
|
||||
pclog("MMIO readw %08X\n", addr);
|
||||
return 0xffff;
|
||||
}
|
||||
uint32_t s3_virge_mmio_read_l(uint32_t addr, void *priv)
|
||||
{
|
||||
pclog("MMIO readl %08X\n", addr);
|
||||
return 0xffffffff;
|
||||
}
|
||||
void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
pclog("MMIO writeb %08X %02X\n", addr, val);
|
||||
}
|
||||
void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
pclog("MMIO writew %08X %04X\n", addr, val);
|
||||
}
|
||||
void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
pclog("MMIO writel %08X %08X\n", addr, val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void s3_virge_hwcursor_draw(int displine)
|
||||
{
|
||||
int x;
|
||||
uint16_t dat[2];
|
||||
int xx;
|
||||
int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff;
|
||||
|
||||
pclog("HWcursor %i %i\n", svga_hwcursor_latch.x, svga_hwcursor_latch.y);
|
||||
for (x = 0; x < 64; x += 16)
|
||||
{
|
||||
dat[0] = (vram[svga_hwcursor_latch.addr] << 8) | vram[svga_hwcursor_latch.addr + 1];
|
||||
dat[1] = (vram[svga_hwcursor_latch.addr + 2] << 8) | vram[svga_hwcursor_latch.addr + 3];
|
||||
for (xx = 0; xx < 16; xx++)
|
||||
{
|
||||
if (offset >= svga_hwcursor_latch.x)
|
||||
{
|
||||
if (!(dat[0] & 0x8000))
|
||||
((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0;
|
||||
else if (dat[1] & 0x8000)
|
||||
((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff;
|
||||
// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]);
|
||||
}
|
||||
|
||||
offset++;
|
||||
dat[0] <<= 1;
|
||||
dat[1] <<= 1;
|
||||
}
|
||||
svga_hwcursor_latch.addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t s3_virge_pci_regs[256];
|
||||
|
||||
uint8_t s3_virge_pci_read(int func, int addr, void *priv)
|
||||
{
|
||||
// pclog("S3 PCI read %08X\n", addr);
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: return 0x33; /*'S3'*/
|
||||
case 0x01: return 0x53;
|
||||
|
||||
case 0x02: return s3_virge_id_low;
|
||||
case 0x03: return s3_virge_id_high;
|
||||
|
||||
case 0x08: return 0; /*Revision ID*/
|
||||
case 0x09: return 0; /*Programming interface*/
|
||||
|
||||
case 0x0a: return 0x00; /*Supports VGA interface*/
|
||||
case 0x0b: return 0x03;
|
||||
|
||||
case 0x10: return 0x00; /*Linear frame buffer address*/
|
||||
case 0x11: return 0x00;
|
||||
case 0x12: return 0x00;
|
||||
case 0x13: return crtc[0x59] & 0xfc;
|
||||
|
||||
case 0x30: return 0x01; /*BIOS ROM address*/
|
||||
case 0x31: return 0x00;
|
||||
case 0x32: return 0x0C;
|
||||
case 0x33: return 0x00;
|
||||
|
||||
}
|
||||
return s3_virge_pci_regs[addr];
|
||||
}
|
||||
|
||||
void s3_virge_pci_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x3d: case 0x3e: case 0x3f:
|
||||
break;
|
||||
|
||||
case 0x13: crtc[0x59] = val & 0xfc; s3_virge_updatemapping(); break;
|
||||
}
|
||||
s3_virge_pci_regs[addr] = val;
|
||||
}
|
||||
|
||||
int s3_virge_init()
|
||||
{
|
||||
s3_virge_pci_regs[4] = 3;
|
||||
s3_virge_pci_regs[5] = 0;
|
||||
s3_virge_pci_regs[6] = 0;
|
||||
s3_virge_pci_regs[7] = 2;
|
||||
s3_virge_pci_regs[0x3d] = 1;
|
||||
s3_virge_pci_regs[0x3e] = 4;
|
||||
s3_virge_pci_regs[0x3f] = 0xff;
|
||||
|
||||
s3_virge_id_high = 0x56;
|
||||
s3_virge_id_low = 0x31;
|
||||
s3_virge_rev = 0;
|
||||
s3_virge_id = 0xe1;
|
||||
|
||||
svga_recalctimings_ex = s3_virge_recalctimings;
|
||||
svga_hwcursor_draw = s3_virge_hwcursor_draw;
|
||||
|
||||
crtc[0x36] = 1 | (2 << 2) | (1 << 4) | (4 << 5);
|
||||
crtc[0x37] = 1 | (7 << 5);
|
||||
|
||||
vrammask = 0x3fffff;
|
||||
|
||||
pci_add(s3_virge_pci_read, s3_virge_pci_write, NULL);
|
||||
|
||||
svga_vram_limit = 4 << 20; /*4mb*/
|
||||
return svga_init();
|
||||
}
|
||||
|
||||
GFXCARD vid_s3_virge =
|
||||
{
|
||||
s3_virge_init,
|
||||
/*IO at 3Cx/3Dx*/
|
||||
s3_virge_out,
|
||||
s3_virge_in,
|
||||
/*IO at 3Ax/3Bx*/
|
||||
video_out_null,
|
||||
video_in_null,
|
||||
|
||||
svga_poll,
|
||||
svga_recalctimings,
|
||||
|
||||
svga_write,
|
||||
video_write_null,
|
||||
video_write_null,
|
||||
|
||||
svga_read,
|
||||
video_read_null,
|
||||
video_read_null
|
||||
};
|
||||
|
||||
487
src/vid_svga_render.c
Normal file
487
src/vid_svga_render.c
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
#include "ibm.h"
|
||||
#include "video.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_svga_render.h"
|
||||
|
||||
void svga_render_blank()
|
||||
{
|
||||
int x, xx;
|
||||
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
for (x=0;x<svga_hdisp;x++)
|
||||
{
|
||||
switch (seqregs[1]&9)
|
||||
{
|
||||
case 0:
|
||||
for (xx=0;xx<9;xx++) ((uint32_t *)buffer32->line[displine])[(x*9)+xx+32]=0;
|
||||
break;
|
||||
case 1:
|
||||
for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[(x*8)+xx+32]=0;
|
||||
break;
|
||||
case 8:
|
||||
for (xx=0;xx<18;xx++) ((uint32_t *)buffer32->line[displine])[(x*18)+xx+32]=0;
|
||||
break;
|
||||
case 9:
|
||||
for (xx=0;xx<16;xx++) ((uint32_t *)buffer32->line[displine])[(x*16)+xx+32]=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_text_40()
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
if (fullchange)
|
||||
{
|
||||
int x, xx;
|
||||
int drawcursor;
|
||||
uint8_t chr, attr, dat;
|
||||
uint32_t charaddr;
|
||||
int fg, bg;
|
||||
int xinc = (seqregs[1] & 1) ? 16 : 18;
|
||||
|
||||
for (x=0;x<svga_hdisp;x+=xinc)
|
||||
{
|
||||
drawcursor=((ma==ca) && con && cursoron);
|
||||
chr=vram[(ma<<1)];
|
||||
attr=vram[(ma<<1)+4];
|
||||
if (attr&8) charaddr=charsetb+(chr*128);
|
||||
else charaddr=charseta+(chr*128);
|
||||
|
||||
if (drawcursor)
|
||||
{
|
||||
bg=pallook[egapal[attr&15]];
|
||||
fg=pallook[egapal[attr>>4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg=pallook[egapal[attr&15]];
|
||||
bg=pallook[egapal[attr>>4]];
|
||||
if (attr&0x80 && attrregs[0x10]&8)
|
||||
{
|
||||
bg=pallook[egapal[(attr>>4)&7]];
|
||||
if (cgablink&16) fg=bg;
|
||||
}
|
||||
}
|
||||
|
||||
dat=vram[charaddr+(sc<<2)];
|
||||
if (seqregs[1]&1)
|
||||
{
|
||||
for (xx=0;xx<8;xx++)
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[(x+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx=0;xx<8;xx++)
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[(x+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg;
|
||||
if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4))
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+16)&2047]=((uint32_t *)buffer32->line[displine])[(x+32+17)&2047]=bg;
|
||||
else
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+16)&2047]=((uint32_t *)buffer32->line[displine])[(x+32+17)&2047]=(dat&1)?fg:bg;
|
||||
}
|
||||
ma+=4; ma&=vrammask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_text_80()
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
if (fullchange)
|
||||
{
|
||||
int x, xx;
|
||||
int drawcursor;
|
||||
uint8_t chr, attr, dat;
|
||||
uint32_t charaddr;
|
||||
int fg, bg;
|
||||
int xinc = (seqregs[1] & 1) ? 8 : 9;
|
||||
|
||||
for (x=0;x<svga_hdisp;x+=xinc)
|
||||
{
|
||||
drawcursor=((ma==ca) && con && cursoron);
|
||||
chr=vram[(ma<<1)];
|
||||
attr=vram[(ma<<1)+4];
|
||||
if (attr&8) charaddr=charsetb+(chr*128);
|
||||
else charaddr=charseta+(chr*128);
|
||||
|
||||
if (drawcursor)
|
||||
{
|
||||
bg=pallook[egapal[attr&15]];
|
||||
fg=pallook[egapal[attr>>4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg=pallook[egapal[attr&15]];
|
||||
bg=pallook[egapal[attr>>4]];
|
||||
if (attr&0x80 && attrregs[0x10]&8)
|
||||
{
|
||||
bg=pallook[egapal[(attr>>4)&7]];
|
||||
if (cgablink&16) fg=bg;
|
||||
}
|
||||
}
|
||||
|
||||
dat=vram[charaddr+(sc<<2)];
|
||||
if (seqregs[1]&1)
|
||||
{
|
||||
for (xx=0;xx<8;xx++)
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx=0;xx<8;xx++)
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg;
|
||||
if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4))
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+8)&2047]=bg;
|
||||
else
|
||||
((uint32_t *)buffer32->line[displine])[(x+32+8)&2047]=(dat&1)?fg:bg;
|
||||
}
|
||||
ma+=4; ma&=vrammask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_4bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint8_t edat[4], dat;
|
||||
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=((8-scrollcache)<<1)+16;
|
||||
for (x = 0; x <= svga_hdisp; x += 16)
|
||||
{
|
||||
edat[0]=vram[ma];
|
||||
edat[1]=vram[ma|0x1];
|
||||
edat[2]=vram[ma|0x2];
|
||||
edat[3]=vram[ma|0x3];
|
||||
ma+=4; ma&=vrammask;
|
||||
|
||||
dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+14+offset]=((uint32_t *)buffer32->line[displine])[x+15+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+12+offset]=((uint32_t *)buffer32->line[displine])[x+13+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+10+offset]=((uint32_t *)buffer32->line[displine])[x+11+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+8+offset]= ((uint32_t *)buffer32->line[displine])[x+9+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[dat>>4]];
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_4bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint8_t edat[4], dat;
|
||||
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-scrollcache)+24;
|
||||
for (x = 0; x <= svga_hdisp; x += 8)
|
||||
{
|
||||
edat[0]=vram[ma];
|
||||
edat[1]=vram[ma|0x1];
|
||||
edat[2]=vram[ma|0x2];
|
||||
edat[3]=vram[ma|0x3];
|
||||
ma+=4; ma&=vrammask;
|
||||
|
||||
dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+6+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+4+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]=pallook[egapal[dat>>4]];
|
||||
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[dat&0xF]];
|
||||
((uint32_t *)buffer32->line[displine])[x+offset]= pallook[egapal[dat>>4]];
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_2bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint8_t edat[4], dat;
|
||||
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
offset=((8-scrollcache)<<1)+16;
|
||||
/*Low res (320) only, though high res (640) should be possible*/
|
||||
for (x = 0; x <= svga_hdisp; x += 16)
|
||||
{
|
||||
if (sc&1 && !(crtc[0x17]&1))
|
||||
{
|
||||
edat[0]=vram[(ma<<1)+0x8000];
|
||||
edat[1]=vram[(ma<<1)+0x8004];
|
||||
}
|
||||
else
|
||||
{
|
||||
edat[0]=vram[(ma<<1)];
|
||||
edat[1]=vram[(ma<<1)+4];
|
||||
}
|
||||
ma+=4; ma&=vrammask;
|
||||
|
||||
((uint32_t *)buffer32->line[displine])[x+14+offset]=((uint32_t *)buffer32->line[displine])[x+15+offset]=pallook[egapal[edat[1]&3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+12+offset]=((uint32_t *)buffer32->line[displine])[x+13+offset]=pallook[egapal[(edat[1]>>2)&3]];
|
||||
dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+10+offset]=((uint32_t *)buffer32->line[displine])[x+11+offset]=pallook[egapal[(edat[1]>>4)&3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+8+offset]= ((uint32_t *)buffer32->line[displine])[x+9+offset]=pallook[egapal[(edat[1]>>6)&3]];
|
||||
dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[egapal[(edat[0]>>0)&3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[egapal[(edat[0]>>2)&3]];
|
||||
dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2);
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[egapal[(edat[0]>>4)&3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[egapal[(edat[0]>>6)&3]];
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_8bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint8_t edat[4];
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-(scrollcache&6))+24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 8)
|
||||
{
|
||||
edat[0]=vram[ma];
|
||||
edat[1]=vram[ma|0x1];
|
||||
edat[2]=vram[ma|0x2];
|
||||
edat[3]=vram[ma|0x3];
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x+6+offset]= ((uint32_t *)buffer32->line[displine])[x+7+offset]=pallook[edat[3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+4+offset]= ((uint32_t *)buffer32->line[displine])[x+5+offset]=pallook[edat[2]];
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]= ((uint32_t *)buffer32->line[displine])[x+3+offset]=pallook[edat[1]];
|
||||
((uint32_t *)buffer32->line[displine])[x+offset]= ((uint32_t *)buffer32->line[displine])[x+1+offset]=pallook[edat[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_8bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint8_t edat[4];
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset = (8 - ((scrollcache & 6) >> 1)) + 24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 8)
|
||||
{
|
||||
edat[0]=vram[ma];
|
||||
edat[1]=vram[ma|0x1];
|
||||
edat[2]=vram[ma|0x2];
|
||||
edat[3]=vram[ma|0x3];
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x+3+offset] = pallook[edat[3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset] = pallook[edat[2]];
|
||||
((uint32_t *)buffer32->line[displine])[x+1+offset] = pallook[edat[1]];
|
||||
((uint32_t *)buffer32->line[displine])[x+offset] = pallook[edat[0]];
|
||||
edat[0]=vram[ma];
|
||||
edat[1]=vram[ma|0x1];
|
||||
edat[2]=vram[ma|0x2];
|
||||
edat[3]=vram[ma|0x3];
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x+7+offset] = pallook[edat[3]];
|
||||
((uint32_t *)buffer32->line[displine])[x+6+offset] = pallook[edat[2]];
|
||||
((uint32_t *)buffer32->line[displine])[x+5+offset] = pallook[edat[1]];
|
||||
((uint32_t *)buffer32->line[displine])[x+4+offset] = pallook[edat[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_15bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint16_t fg, bg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-(scrollcache&6))+24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 4)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma|0x1]<<8);
|
||||
bg=vram[ma|0x2]|(vram[ma|0x3]<<8);
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]=((uint32_t *)buffer32->line[displine])[x+3+offset]=((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19);
|
||||
((uint32_t *)buffer32->line[displine])[x+0+offset]=((uint32_t *)buffer32->line[displine])[x+1+offset]=((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_15bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint16_t fg, bg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset = (8 - ((scrollcache & 6) >> 1)) + 24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 2)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma|0x1]<<8);
|
||||
bg=vram[ma|0x2]|(vram[ma|0x3]<<8);
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x + 1 + offset] = ((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19);
|
||||
((uint32_t *)buffer32->line[displine])[x + 0 + offset] = ((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_16bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint16_t fg, bg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-(scrollcache&6))+24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 4)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma|0x1]<<8);
|
||||
bg=vram[ma|0x2]|(vram[ma|0x3]<<8);
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x+2+offset]=((uint32_t *)buffer32->line[displine])[x+3+offset]=((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19);
|
||||
((uint32_t *)buffer32->line[displine])[x+0+offset]=((uint32_t *)buffer32->line[displine])[x+1+offset]=((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_16bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint16_t fg, bg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset = (8 - ((scrollcache & 6) >> 1)) + 24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x += 2)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma|0x1]<<8);
|
||||
bg=vram[ma|0x2]|(vram[ma|0x3]<<8);
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x + 1 + offset] = ((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19);
|
||||
((uint32_t *)buffer32->line[displine])[x + 0 + offset] = ((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_24bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint32_t fg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-(scrollcache&6))+24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x++)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16);
|
||||
ma+=3; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[(x<<1)+offset]=((uint32_t *)buffer32->line[displine])[(x<<1)+1+offset]=fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_24bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint32_t fg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset = (8 - ((scrollcache & 6) >> 1)) + 24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x++)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16);
|
||||
ma+=3; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x + offset] = fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_32bpp_lowres()
|
||||
{
|
||||
int x, offset;
|
||||
uint32_t fg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset=(8-(scrollcache&6))+24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x++)
|
||||
{
|
||||
fg = vram[ma] | (vram[ma + 1] << 8) | (vram[ma + 2] << 16);
|
||||
ma += 4; ma &= vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[displine])[(x << 1) + 1 + offset] = fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_32bpp_highres()
|
||||
{
|
||||
int x, offset;
|
||||
uint32_t fg;
|
||||
|
||||
if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange)
|
||||
{
|
||||
if (firstline_draw == 2000) firstline_draw = displine;
|
||||
lastline_draw = displine;
|
||||
|
||||
offset = (8 - ((scrollcache & 6) >> 1)) + 24;
|
||||
|
||||
for (x = 0; x <= svga_hdisp; x++)
|
||||
{
|
||||
fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16);
|
||||
ma+=4; ma&=vrammask;
|
||||
((uint32_t *)buffer32->line[displine])[x + offset] = fg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
src/vid_svga_render.h
Normal file
30
src/vid_svga_render.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
extern int firstline_draw, lastline_draw;
|
||||
extern int displine;
|
||||
extern int sc;
|
||||
|
||||
extern uint32_t ma, ca;
|
||||
extern int con, cursoron, cgablink;
|
||||
|
||||
extern int scrollcache;
|
||||
|
||||
extern uint8_t edatlookup[4][4];
|
||||
|
||||
void svga_render_blank();
|
||||
void svga_render_text_40();
|
||||
void svga_render_text_80();
|
||||
|
||||
void svga_render_2bpp_lowres();
|
||||
void svga_render_4bpp_lowres();
|
||||
void svga_render_4bpp_highres();
|
||||
void svga_render_8bpp_lowres();
|
||||
void svga_render_8bpp_highres();
|
||||
void svga_render_15bpp_lowres();
|
||||
void svga_render_15bpp_highres();
|
||||
void svga_render_16bpp_lowres();
|
||||
void svga_render_16bpp_highres();
|
||||
void svga_render_24bpp_lowres();
|
||||
void svga_render_24bpp_highres();
|
||||
void svga_render_32bpp_lowres();
|
||||
void svga_render_32bpp_highres();
|
||||
|
||||
extern void (*svga_render)();
|
||||
92
src/vid_vga.c
Normal file
92
src/vid_vga.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*IBM VGA emulation*/
|
||||
#include "ibm.h"
|
||||
#include "io.h"
|
||||
#include "video.h"
|
||||
#include "vid_svga.h"
|
||||
|
||||
void vga_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
pclog("vga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,pc, ram[0x489], ins);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3D4:
|
||||
crtcreg = val & 0x1f;
|
||||
return;
|
||||
case 0x3D5:
|
||||
if (crtcreg <= 7 && crtc[0x11] & 0x80) return;
|
||||
old=crtc[crtcreg];
|
||||
crtc[crtcreg]=val;
|
||||
if (old!=val)
|
||||
{
|
||||
if (crtcreg<0xE || crtcreg>0x10)
|
||||
{
|
||||
fullchange=changeframecount;
|
||||
svga_recalctimings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
svga_out(addr, val, NULL);
|
||||
}
|
||||
|
||||
uint8_t vga_in(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
if (addr != 0x3da) pclog("vga_in : %04X ", addr);
|
||||
|
||||
if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3D4:
|
||||
temp = crtcreg;
|
||||
break;
|
||||
case 0x3D5:
|
||||
temp = crtc[crtcreg];
|
||||
break;
|
||||
default:
|
||||
temp = svga_in(addr, NULL);
|
||||
break;
|
||||
}
|
||||
if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc);
|
||||
return temp;
|
||||
}
|
||||
|
||||
int vga_init()
|
||||
{
|
||||
svga_recalctimings_ex = NULL;
|
||||
svga_vram_limit = 1 << 18; /*256kb*/
|
||||
vrammask = 0x3ffff;
|
||||
svgawbank = svgarbank = 0;
|
||||
bpp = 8;
|
||||
svga_miscout = 1;
|
||||
return svga_init();
|
||||
}
|
||||
|
||||
GFXCARD vid_vga =
|
||||
{
|
||||
vga_init,
|
||||
/*IO at 3Cx/3Dx*/
|
||||
vga_out,
|
||||
vga_in,
|
||||
/*IO at 3Ax/3Bx*/
|
||||
video_out_null,
|
||||
video_in_null,
|
||||
|
||||
svga_poll,
|
||||
svga_recalctimings,
|
||||
|
||||
svga_write,
|
||||
video_write_null,
|
||||
video_write_null,
|
||||
|
||||
svga_read,
|
||||
video_read_null,
|
||||
video_read_null
|
||||
};
|
||||
732
src/vid_voodoo.c
Normal file
732
src/vid_voodoo.c
Normal file
|
|
@ -0,0 +1,732 @@
|
|||
#include <stdlib.h>
|
||||
#include "ibm.h"
|
||||
#include "mem.h"
|
||||
#include "pci.h"
|
||||
#include "vid_voodoo.h"
|
||||
|
||||
static int tris = 0;
|
||||
|
||||
static struct voodoo
|
||||
{
|
||||
int pci_enable;
|
||||
|
||||
uint32_t color0, color1;
|
||||
|
||||
uint8_t dac_data[8];
|
||||
int dac_reg;
|
||||
uint8_t dac_readdata;
|
||||
|
||||
uint32_t dRdX, dGdX, dBdX, dZdX, dAdX, dSdX, dTdX, dWdX;
|
||||
|
||||
uint32_t dRdY, dGdY, dBdY, dZdY, dAdY, dSdY, dTdY, dWdY;
|
||||
|
||||
uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4;
|
||||
|
||||
uint32_t fbzMode;
|
||||
|
||||
uint8_t initEnable;
|
||||
|
||||
uint32_t lfbMode;
|
||||
|
||||
uint32_t memBaseAddr;
|
||||
|
||||
uint32_t startR, startG, startB, startZ, startA, startS, startT, startW;
|
||||
|
||||
uint32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy;
|
||||
|
||||
uint32_t front_offset, back_offset, aux_offset;
|
||||
|
||||
uint32_t fb_read_offset, fb_write_offset;
|
||||
|
||||
uint32_t draw_offset;
|
||||
|
||||
int row_width;
|
||||
|
||||
uint8_t *fb_mem, *tex_mem;
|
||||
} voodoo;
|
||||
|
||||
enum
|
||||
{
|
||||
SST_status = 0x000,
|
||||
|
||||
SST_vertexAx = 0x008,
|
||||
SST_vertexAy = 0x00c,
|
||||
SST_vertexBx = 0x010,
|
||||
SST_vertexBy = 0x014,
|
||||
SST_vertexCx = 0x018,
|
||||
SST_vertexCy = 0x01c,
|
||||
|
||||
SST_startR = 0x0020,
|
||||
SST_startG = 0x0024,
|
||||
SST_startB = 0x0028,
|
||||
SST_startZ = 0x002c,
|
||||
SST_startA = 0x0030,
|
||||
SST_startS = 0x0034,
|
||||
SST_startT = 0x0038,
|
||||
SST_startW = 0x003c,
|
||||
|
||||
SST_dRdX = 0x0040,
|
||||
SST_dGdX = 0x0044,
|
||||
SST_dBdX = 0x0048,
|
||||
SST_dZdX = 0x004c,
|
||||
SST_dAdX = 0x0050,
|
||||
SST_dSdX = 0x0054,
|
||||
SST_dTdX = 0x0058,
|
||||
SST_dWdX = 0x005c,
|
||||
|
||||
SST_dRdY = 0x0060,
|
||||
SST_dGdY = 0x0064,
|
||||
SST_dBdY = 0x0068,
|
||||
SST_dZdY = 0x006c,
|
||||
SST_dAdY = 0x0070,
|
||||
SST_dSdY = 0x0074,
|
||||
SST_dTdY = 0x0078,
|
||||
SST_dWdY = 0x007c,
|
||||
|
||||
SST_triangleCMD = 0x0080,
|
||||
|
||||
SST_fbzMode = 0x110,
|
||||
SST_lfbMode = 0x114,
|
||||
SST_swapbufferCMD = 0x128,
|
||||
|
||||
SST_color0 = 0x144,
|
||||
SST_color1 = 0x148,
|
||||
|
||||
SST_fbiInit4 = 0x200,
|
||||
SST_fbiInit0 = 0x210,
|
||||
SST_fbiInit1 = 0x214,
|
||||
SST_fbiInit2 = 0x218,
|
||||
SST_fbiInit3 = 0x21c,
|
||||
SST_dacData = 0x22c
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LFB_WRITE_FRONT = 0x0000,
|
||||
LFB_WRITE_BACK = 0x0010,
|
||||
LFB_WRITE_MASK = 0x0030
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LFB_READ_FRONT = 0x0000,
|
||||
LFB_READ_BACK = 0x0040,
|
||||
LFB_READ_AUX = 0x0080,
|
||||
LFB_READ_MASK = 0x00c0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LFB_FORMAT_RGB565 = 0,
|
||||
LFB_FORMAT_DEPTH = 15,
|
||||
LFB_FORMAT_MASK = 15
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LFB_WRITE_COLOUR = 1,
|
||||
LFB_WRITE_DEPTH = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FBZ_DITHER = 0x100,
|
||||
FBZ_DRAWRGB = 0x200,
|
||||
|
||||
FBZ_DRAW_FRONT = 0x0000,
|
||||
FBZ_DRAW_BACK = 0x4000,
|
||||
FBZ_DRAW_MASK = 0xc000
|
||||
};
|
||||
|
||||
static int voodoo_reads = 0;
|
||||
|
||||
static void voodoo_recalc()
|
||||
{
|
||||
uint32_t buffer_offset = ((voodoo.fbiInit2 >> 11) & 511) * 4096;
|
||||
|
||||
voodoo.front_offset = 0;
|
||||
voodoo.back_offset = buffer_offset;
|
||||
voodoo.aux_offset = buffer_offset * 2;
|
||||
|
||||
switch (voodoo.lfbMode & LFB_WRITE_MASK)
|
||||
{
|
||||
case LFB_WRITE_FRONT:
|
||||
voodoo.fb_write_offset = voodoo.front_offset;
|
||||
break;
|
||||
case LFB_WRITE_BACK:
|
||||
voodoo.fb_write_offset = voodoo.back_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_recalc : unknown lfb destination\n");
|
||||
}
|
||||
|
||||
switch (voodoo.lfbMode & LFB_READ_MASK)
|
||||
{
|
||||
case LFB_READ_FRONT:
|
||||
voodoo.fb_read_offset = voodoo.front_offset;
|
||||
break;
|
||||
case LFB_READ_BACK:
|
||||
voodoo.fb_read_offset = voodoo.back_offset;
|
||||
break;
|
||||
case LFB_READ_AUX:
|
||||
voodoo.fb_read_offset = voodoo.aux_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_recalc : unknown lfb source\n");
|
||||
}
|
||||
|
||||
switch (voodoo.fbzMode & FBZ_DRAW_MASK)
|
||||
{
|
||||
case FBZ_DRAW_FRONT:
|
||||
voodoo.draw_offset = voodoo.front_offset;
|
||||
break;
|
||||
case FBZ_DRAW_BACK:
|
||||
voodoo.draw_offset = voodoo.back_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_recalc : unknown draw buffer\n");
|
||||
}
|
||||
|
||||
voodoo.row_width = ((voodoo.fbiInit1 >> 4) & 15) * 64 * 2;
|
||||
pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X\n", voodoo.front_offset, voodoo.back_offset, voodoo.aux_offset);
|
||||
pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i\n", voodoo.fb_read_offset, voodoo.fb_write_offset, voodoo.row_width);
|
||||
}
|
||||
|
||||
static int dither_matrix_4x4[16] =
|
||||
{
|
||||
0, 8, 2, 10,
|
||||
12, 4, 14, 6,
|
||||
3, 11, 1, 9,
|
||||
15, 7, 13, 5
|
||||
};
|
||||
|
||||
static int dither_rb[256][4][4];
|
||||
static int dither_g[256][4][4];
|
||||
|
||||
static void voodoo_make_dither()
|
||||
{
|
||||
int c, x, y;
|
||||
int seen_rb[1024];
|
||||
int seen_g[1024];
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
int rb = (int)(((double)c * 496.0) / 256.0);
|
||||
int g = (int)(((double)c * 1008.0) / 256.0);
|
||||
pclog("rb %i %i\n", rb, c);
|
||||
for (y = 0; y < 4; y++)
|
||||
{
|
||||
for (x = 0; x < 4; x++)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = rb + dither_matrix_4x4[x + (y << 2)];
|
||||
dither_rb[c][y][x] = val >> 4;
|
||||
pclog("RB %i %i, %i %i %i %i\n", c, x, y, val, val >> 4, dither_rb[c][y][x]);
|
||||
|
||||
if (dither_rb[c][y][x] > 31)
|
||||
fatal("RB overflow %i %i %i %i\n", c, x, y, dither_rb[c][y][x]);
|
||||
|
||||
val = g + dither_matrix_4x4[x + (y << 2)];
|
||||
dither_g[c][y][x] = val >> 4;
|
||||
|
||||
if (dither_g[c][y][x] > 63)
|
||||
fatal("G overflow %i %i %i %i\n", c, x, y, dither_g[c][y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(seen_rb, 0, sizeof(seen_rb));
|
||||
memset(seen_g, 0, sizeof(seen_g));
|
||||
|
||||
for (c = 0; c < 256; c++)
|
||||
{
|
||||
int total_rb = 0;
|
||||
int total_g = 0;
|
||||
for (y = 0; y < 4; y++)
|
||||
{
|
||||
for (x = 0; x < 4; x++)
|
||||
{
|
||||
total_rb += dither_rb[c][y][x];
|
||||
pclog("total_rb %i %i, %i %i %i\n", c, x, y, total_rb, dither_rb[c][y][x]);
|
||||
total_g += dither_g[c][y][x];
|
||||
}
|
||||
}
|
||||
|
||||
if (seen_rb[total_rb])
|
||||
fatal("Duplicate rb %i %i\n", c, total_rb);
|
||||
seen_rb[total_rb] = 1;
|
||||
|
||||
if (seen_g[total_g])
|
||||
fatal("Duplicate g %i %i\n", c, total_g);
|
||||
seen_g[total_g] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void voodoo_triangle(struct voodoo *voodoo)
|
||||
{
|
||||
int y, yend, ydir;
|
||||
int xstart, xend, xdir;
|
||||
int dx1, dx2;
|
||||
|
||||
pclog("voodoo_triangle %i : vA %f, %f vB %f, %f vC %f, %f\n", tris, (float)voodoo->vertexAx / 16.0, (float)voodoo->vertexAy / 16.0,
|
||||
(float)voodoo->vertexBx / 16.0, (float)voodoo->vertexBy / 16.0,
|
||||
(float)voodoo->vertexCx / 16.0, (float)voodoo->vertexCy / 16.0);
|
||||
// output = 3;
|
||||
tris++;
|
||||
// if (tris == 3)
|
||||
// fatal("tris 2\n");
|
||||
|
||||
y = voodoo->vertexAy >> 4;
|
||||
ydir = (voodoo->vertexAy >= voodoo->vertexCy) ? -1 : 1;
|
||||
|
||||
if (voodoo->vertexAy == voodoo->vertexBy)
|
||||
{
|
||||
xstart = voodoo->vertexAx << 8;
|
||||
xend = voodoo->vertexBx << 8;
|
||||
}
|
||||
else
|
||||
xstart = xend = voodoo->vertexAx << 8;
|
||||
xdir = (xstart >= xend) ? -1 : 1;
|
||||
|
||||
if (voodoo->vertexAy != voodoo->vertexBy)
|
||||
{
|
||||
/*Draw top half*/
|
||||
dx1 = (int)(((voodoo->vertexBx << 8) - xstart) << 4) / (int)((voodoo->vertexBy - voodoo->vertexAy) * ydir);
|
||||
dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
||||
yend = voodoo->vertexBy >> 4;
|
||||
|
||||
pclog("voodoo_triangle : top-half %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, xdir, y, yend, ydir);
|
||||
|
||||
for (; y != yend; y += ydir)
|
||||
{
|
||||
pclog(" %i : %i - %i\n", xstart >> 12, xend >> 12);
|
||||
xstart += dx1;
|
||||
xend += dx2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (voodoo->vertexBy != voodoo->vertexCy)
|
||||
{
|
||||
/*Draw bottom half*/
|
||||
dx1 = (int)(((voodoo->vertexCx << 8) - xstart) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
||||
dx2 = (int)(((voodoo->vertexCx << 8) - xend) << 4) / (int)((voodoo->vertexCy - voodoo->vertexAy) * ydir);
|
||||
yend = voodoo->vertexCy >> 4;
|
||||
|
||||
pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir);
|
||||
|
||||
for (; y != yend; y += ydir)
|
||||
{
|
||||
int x = xstart >> 12, x2 = xend >> 12;
|
||||
pclog(" %i : %i - %i\n", y, x, x2);
|
||||
|
||||
for (; x != x2; x += xdir)
|
||||
{
|
||||
if (voodoo->fbzMode & FBZ_DRAWRGB)
|
||||
{
|
||||
int r = (voodoo->color1 >> 16) & 0xff;
|
||||
int g = (voodoo->color1 >> 8) & 0xff;
|
||||
int b = voodoo->color1 & 0xff;
|
||||
if (voodoo->fbzMode & FBZ_DITHER)
|
||||
{
|
||||
r = dither_rb[r][y & 3][x & 3];
|
||||
g = dither_g[g][y & 3][x & 3];
|
||||
b = dither_rb[b][y & 3][x & 3];
|
||||
/* r = ((r << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
||||
g = ((g << 2) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
||||
b = ((b << 1) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 4;
|
||||
if (r > 31) r = 31;
|
||||
if (g > 63) g = 63;
|
||||
if (b > 31) b = 31;*/
|
||||
/* r = (((r << 1) - (r >> 4) + (r >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3;
|
||||
g = (((g << 2) - (g >> 4) + (g >> 6) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 2) >> 2;
|
||||
b = (((b << 1) - (b >> 4) + (b >> 7) + dither_matrix_4x4[(x & 3) + ((y & 3) << 2)]) >> 1) >> 3;*/
|
||||
}
|
||||
else
|
||||
{
|
||||
r >>= 3;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
}
|
||||
*(uint16_t *)(&voodoo->fb_mem[voodoo->draw_offset + (y * voodoo->row_width) + (x << 1)]) = b | (g << 5) | (r << 11);
|
||||
pclog(" %i = %i %i %i %04X %08X %08X\n", x, r, g, b, b | (g << 5) | (r << 11), voodoo->draw_offset + (y * voodoo->row_width) + (x << 1), *(uint32_t *)(&voodoo->fb_mem[4]));
|
||||
}
|
||||
}
|
||||
xstart += dx1;
|
||||
xend += dx2;
|
||||
}
|
||||
}
|
||||
|
||||
/* for (y = ystart, y != yend; y += ydir)
|
||||
{
|
||||
if (voodoo.fbzMode & FBZ_DITHER
|
||||
}*/
|
||||
}
|
||||
|
||||
static uint32_t voodoo_readl(uint32_t addr, void *priv)
|
||||
{
|
||||
uint32_t temp;
|
||||
switch (addr & 0x3fc)
|
||||
{
|
||||
case SST_status:
|
||||
temp = 0x0ffff03f; /*FIFOs empty*/
|
||||
break;
|
||||
|
||||
case SST_lfbMode:
|
||||
return voodoo.lfbMode;
|
||||
|
||||
case SST_fbiInit4:
|
||||
temp = voodoo.fbiInit4;
|
||||
break;
|
||||
case SST_fbiInit0:
|
||||
temp = voodoo.fbiInit0;
|
||||
break;
|
||||
case SST_fbiInit1:
|
||||
temp = voodoo.fbiInit1 & ~5; /*Pass-thru board with one SST-1*/
|
||||
break;
|
||||
case SST_fbiInit2:
|
||||
if (voodoo.initEnable & 0x04)
|
||||
temp = voodoo.dac_readdata;
|
||||
else
|
||||
temp = voodoo.fbiInit2;
|
||||
break;
|
||||
case SST_fbiInit3:
|
||||
temp = voodoo.fbiInit3;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_readl : bad addr %08X\n", addr);
|
||||
temp = 0xffffffff;
|
||||
}
|
||||
pclog("voodoo_readl : addr %08X val %08X %04X(%08X):%08X %i\n", addr, temp, CS, cs, pc, voodoo_reads++);
|
||||
// if (voodoo_reads == 200494)
|
||||
// output = 3;
|
||||
return temp;
|
||||
}
|
||||
|
||||
static void voodoo_writel(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
pclog("voodoo_writel : addr %08X val %08X %04X(%08X):%08X\n", addr, val, CS, cs, pc);
|
||||
switch (addr & 0x3fc)
|
||||
{
|
||||
case SST_swapbufferCMD:
|
||||
pclog(" start swap buffer command\n");
|
||||
// output = 3;
|
||||
break;
|
||||
|
||||
case SST_vertexAx:
|
||||
voodoo.vertexAx = val & 0xffff;
|
||||
break;
|
||||
case SST_vertexAy:
|
||||
voodoo.vertexAy = val & 0xffff;
|
||||
break;
|
||||
case SST_vertexBx:
|
||||
voodoo.vertexBx = val & 0xffff;
|
||||
break;
|
||||
case SST_vertexBy:
|
||||
voodoo.vertexBy = val & 0xffff;
|
||||
break;
|
||||
case SST_vertexCx:
|
||||
voodoo.vertexCx = val & 0xffff;
|
||||
break;
|
||||
case SST_vertexCy:
|
||||
voodoo.vertexCy = val & 0xffff;
|
||||
break;
|
||||
|
||||
case SST_startR:
|
||||
voodoo.startR = val & 0xffffff;
|
||||
break;
|
||||
case SST_startG:
|
||||
voodoo.startG = val & 0xffffff;
|
||||
break;
|
||||
case SST_startB:
|
||||
voodoo.startB = val & 0xffffff;
|
||||
break;
|
||||
case SST_startZ:
|
||||
voodoo.startZ = val;
|
||||
break;
|
||||
case SST_startA:
|
||||
voodoo.startA = val & 0xffffff;
|
||||
break;
|
||||
case SST_startS:
|
||||
voodoo.startS = val;
|
||||
break;
|
||||
case SST_startT:
|
||||
voodoo.startT = val;
|
||||
break;
|
||||
case SST_startW:
|
||||
voodoo.startW = val;
|
||||
break;
|
||||
|
||||
case SST_dRdX:
|
||||
voodoo.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dGdX:
|
||||
voodoo.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dBdX:
|
||||
voodoo.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dZdX:
|
||||
voodoo.dZdX = val;
|
||||
break;
|
||||
case SST_dAdX:
|
||||
voodoo.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dSdX:
|
||||
voodoo.dSdX = val;
|
||||
break;
|
||||
case SST_dTdX:
|
||||
voodoo.dTdX = val;
|
||||
break;
|
||||
case SST_dWdX:
|
||||
voodoo.dWdX = val;
|
||||
break;
|
||||
|
||||
case SST_dRdY:
|
||||
voodoo.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dGdY:
|
||||
voodoo.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dBdY:
|
||||
voodoo.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dZdY:
|
||||
voodoo.dZdY = val;
|
||||
break;
|
||||
case SST_dAdY:
|
||||
voodoo.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
||||
break;
|
||||
case SST_dSdY:
|
||||
voodoo.dSdY = val;
|
||||
break;
|
||||
case SST_dTdY:
|
||||
voodoo.dTdY = val;
|
||||
break;
|
||||
case SST_dWdY:
|
||||
voodoo.dWdY = val;
|
||||
break;
|
||||
|
||||
case SST_triangleCMD:
|
||||
voodoo_triangle(&voodoo);
|
||||
break;
|
||||
|
||||
|
||||
case SST_fbzMode:
|
||||
voodoo.fbzMode = val;
|
||||
break;
|
||||
case SST_lfbMode:
|
||||
voodoo.lfbMode = val;
|
||||
voodoo_recalc();
|
||||
break;
|
||||
|
||||
case SST_color0:
|
||||
voodoo.color0 = val;
|
||||
break;
|
||||
case SST_color1:
|
||||
voodoo.color1 = val;
|
||||
break;
|
||||
|
||||
case SST_fbiInit4:
|
||||
if (voodoo.initEnable & 0x01)
|
||||
voodoo.fbiInit4 = val;
|
||||
break;
|
||||
case SST_fbiInit0:
|
||||
if (voodoo.initEnable & 0x01)
|
||||
voodoo.fbiInit0 = val;
|
||||
break;
|
||||
case SST_fbiInit1:
|
||||
if (voodoo.initEnable & 0x01)
|
||||
voodoo.fbiInit1 = val;
|
||||
break;
|
||||
case SST_fbiInit2:
|
||||
if (voodoo.initEnable & 0x01)
|
||||
{
|
||||
voodoo.fbiInit2 = val;
|
||||
voodoo_recalc();
|
||||
}
|
||||
break;
|
||||
case SST_fbiInit3:
|
||||
if (voodoo.initEnable & 0x01)
|
||||
voodoo.fbiInit3 = val;
|
||||
break;
|
||||
|
||||
case SST_dacData:
|
||||
voodoo.dac_reg = (val >> 8) & 7;
|
||||
voodoo.dac_readdata = 0xff;
|
||||
if (val & 0x800)
|
||||
{
|
||||
pclog(" dacData read %i %02X\n", voodoo.dac_reg, voodoo.dac_data[7]);
|
||||
if (voodoo.dac_reg == 5)
|
||||
{
|
||||
switch (voodoo.dac_data[7])
|
||||
{
|
||||
case 0x01: voodoo.dac_readdata = 0x55; break;
|
||||
case 0x07: voodoo.dac_readdata = 0x71; break;
|
||||
case 0x0b: voodoo.dac_readdata = 0x79; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
voodoo.dac_readdata = voodoo.dac_data[voodoo.dac_readdata];
|
||||
}
|
||||
else
|
||||
voodoo.dac_data[voodoo.dac_reg] = val & 0xff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t voodoo_fb_readw(uint32_t addr, void *priv)
|
||||
{
|
||||
pclog("voodoo_fb_readw : %08X %04X\n", addr, *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]));
|
||||
return *(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]);
|
||||
}
|
||||
static uint32_t voodoo_fb_readl(uint32_t addr, void *priv)
|
||||
{
|
||||
int x, y;
|
||||
uint32_t read_addr;
|
||||
uint32_t temp;
|
||||
|
||||
x = (addr >> 1) & 0x3ff;
|
||||
y = (addr >> 11) & 0x3ff;
|
||||
read_addr = voodoo.fb_read_offset + (x << 1) + (y * voodoo.row_width);
|
||||
|
||||
temp = *(uint32_t *)(&voodoo.fb_mem[read_addr & 0x1fffff]);
|
||||
|
||||
pclog("voodoo_fb_readl : %08X %08X %i %i %08X %08X\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo.fb_mem[4]));
|
||||
return temp;
|
||||
}
|
||||
static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
pclog("voodoo_fb_writew : %08X %04X\n", addr, val);
|
||||
*(uint16_t *)(&voodoo.fb_mem[addr & 0x1fffff]) = val;
|
||||
}
|
||||
static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
int x, y;
|
||||
uint32_t write_addr, write_addr_aux;
|
||||
uint32_t colour_data, depth_data;
|
||||
int write_mask, count = 1;
|
||||
|
||||
pclog("voodoo_fb_writel : %08X %08X\n", addr, val);
|
||||
|
||||
if (voodoo.lfbMode & 0x100)
|
||||
fatal("voodoo_fb_writel : using pixel processing\n");
|
||||
|
||||
switch (voodoo.lfbMode & LFB_FORMAT_MASK)
|
||||
{
|
||||
case LFB_FORMAT_RGB565:
|
||||
colour_data = val;
|
||||
write_mask = LFB_WRITE_COLOUR;
|
||||
break;
|
||||
|
||||
case LFB_FORMAT_DEPTH:
|
||||
depth_data = val;
|
||||
write_mask = LFB_WRITE_DEPTH;
|
||||
addr <<= 1;
|
||||
count = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo.lfbMode);
|
||||
}
|
||||
|
||||
x = addr & 0x3fe;
|
||||
y = (addr >> 10) & 0x3ff;
|
||||
|
||||
write_addr = voodoo.fb_read_offset + x + (y * voodoo.row_width);
|
||||
write_addr_aux = voodoo.aux_offset + x + (y * voodoo.row_width);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (write_mask & LFB_WRITE_COLOUR)
|
||||
*(uint16_t *)(&voodoo.fb_mem[write_addr & 0x1ffffe]) = colour_data;
|
||||
if (write_mask & LFB_WRITE_DEPTH)
|
||||
*(uint16_t *)(&voodoo.fb_mem[write_addr_aux & 0x1ffffe]) = depth_data;
|
||||
|
||||
colour_data >>= 16;
|
||||
depth_data >>= 16;
|
||||
|
||||
write_addr += 2;
|
||||
write_addr_aux += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void voodoo_tex_writew(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
pclog("voodoo_tex_write : %08X %04X\n", addr, val);
|
||||
*(uint16_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val;
|
||||
}
|
||||
static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
pclog("voodoo_tex_write : %08X %08X\n", addr, val);
|
||||
*(uint32_t *)(&voodoo.tex_mem[addr & 0x1fffff]) = val;
|
||||
}
|
||||
|
||||
static void voodoo_recalcmapping()
|
||||
{
|
||||
mem_removehandler(0x00000000, 0xffffffff, NULL, NULL, voodoo_readl, NULL, NULL, voodoo_writel, NULL);
|
||||
mem_removehandler(0x00000000, 0xffffffff, NULL, voodoo_fb_readw, voodoo_fb_readl, NULL, voodoo_fb_writew, voodoo_fb_writel, NULL);
|
||||
mem_removehandler(0x00000000, 0xffffffff, NULL, NULL, NULL, NULL, voodoo_tex_writew, voodoo_tex_writel, NULL);
|
||||
if (voodoo.pci_enable)
|
||||
{
|
||||
pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo.memBaseAddr);
|
||||
mem_sethandler(voodoo.memBaseAddr, 0x003fffff, NULL, NULL, voodoo_readl, NULL, NULL, voodoo_writel, NULL);
|
||||
mem_sethandler(voodoo.memBaseAddr + 0x00400000, 0x003fffff, NULL, voodoo_fb_readw, voodoo_fb_readl, NULL, voodoo_fb_writew, voodoo_fb_writel, NULL);
|
||||
mem_sethandler(voodoo.memBaseAddr + 0x00800000, 0x007fffff, NULL, NULL, NULL, NULL, voodoo_tex_writew, voodoo_tex_writel, NULL);
|
||||
}
|
||||
else
|
||||
pclog("voodoo_recalcmapping : disabled\n");
|
||||
}
|
||||
|
||||
uint8_t voodoo_pci_read(int func, int addr, void *priv)
|
||||
{
|
||||
pclog("Voodoo PCI read %08X\n", addr);
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: return 0x1a; /*3dfx*/
|
||||
case 0x01: return 0x12;
|
||||
|
||||
case 0x02: return 0x01; /*SST-1 (Voodoo Graphics)*/
|
||||
case 0x03: return 0x00;
|
||||
|
||||
case 0x04: return voodoo.pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/
|
||||
|
||||
case 0x08: return 0; /*Revision ID*/
|
||||
case 0x09: return 0; /*Programming interface*/
|
||||
|
||||
case 0x10: return 0x00; /*memBaseAddr*/
|
||||
case 0x11: return 0x00;
|
||||
case 0x12: return 0x00;
|
||||
case 0x13: return voodoo.memBaseAddr >> 24;
|
||||
|
||||
case 0x40: return voodoo.initEnable;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void voodoo_pci_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
pclog("Voodoo PCI write %04X %02X\n", addr, val);
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04: voodoo.pci_enable = val & 2; voodoo_recalcmapping(); break;
|
||||
|
||||
case 0x13: voodoo.memBaseAddr = val << 24; voodoo_recalcmapping(); break;
|
||||
|
||||
case 0x40: voodoo.initEnable = val; break;
|
||||
}
|
||||
}
|
||||
|
||||
void voodoo_init()
|
||||
{
|
||||
return;
|
||||
voodoo_make_dither();
|
||||
pci_add(voodoo_pci_read, voodoo_pci_write, NULL);
|
||||
voodoo.fb_mem = malloc(2 * 1024 * 1024);
|
||||
voodoo.tex_mem = malloc(2 * 1024 * 1024);
|
||||
}
|
||||
1
src/vid_voodoo.h
Normal file
1
src/vid_voodoo.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
void voodoo_init();
|
||||
12
src/x86_ops.h
Normal file
12
src/x86_ops.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
typedef int (*OpFn)(uint32_t fetchdat);
|
||||
|
||||
void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f);
|
||||
|
||||
extern OpFn *x86_opcodes;
|
||||
extern OpFn *x86_opcodes_0f;
|
||||
|
||||
extern OpFn ops_286[1024];
|
||||
extern OpFn ops_286_0f[1024];
|
||||
|
||||
extern OpFn ops_386[1024];
|
||||
extern OpFn ops_386_0f[1024];
|
||||
645
src/x86_ops_arith.h
Normal file
645
src/x86_ops_arith.h
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
#define OP_ARITH(name, operation, setflags, flagops) \
|
||||
static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_16(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint8_t dst = getr8(rm); \
|
||||
uint8_t src = getr8(reg); \
|
||||
setflags ## 8 flagops; \
|
||||
setr8(rm, operation); \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint8_t dst = geteab(); if (abrt) return 0; \
|
||||
uint8_t src = getr8(reg); \
|
||||
seteab(operation); if (abrt) return 0; \
|
||||
setflags ## 8 flagops; \
|
||||
cycles -= timing_mr; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_32(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint8_t dst = getr8(rm); \
|
||||
uint8_t src = getr8(reg); \
|
||||
setflags ## 8 flagops; \
|
||||
setr8(rm, operation); \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint8_t dst = geteab(); if (abrt) return 0; \
|
||||
uint8_t src = getr8(reg); \
|
||||
seteab(operation); if (abrt) return 0; \
|
||||
setflags ## 8 flagops; \
|
||||
cycles -= timing_mr; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_16(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint16_t dst = regs[rm].w; \
|
||||
uint16_t src = regs[reg].w; \
|
||||
setflags ## 16 flagops; \
|
||||
regs[rm].w = operation; \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint16_t dst = geteaw(); if (abrt) return 0; \
|
||||
uint16_t src = regs[reg].w; \
|
||||
seteaw(operation); if (abrt) return 0; \
|
||||
setflags ## 16 flagops; \
|
||||
cycles -= timing_mr; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_32(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint16_t dst = regs[rm].w; \
|
||||
uint16_t src = regs[reg].w; \
|
||||
setflags ## 16 flagops; \
|
||||
regs[rm].w = operation; \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint16_t dst = geteaw(); if (abrt) return 0; \
|
||||
uint16_t src = regs[reg].w; \
|
||||
seteaw(operation); if (abrt) return 0; \
|
||||
setflags ## 16 flagops; \
|
||||
cycles -= timing_mr; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_16(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint32_t dst = regs[rm].l; \
|
||||
uint32_t src = regs[reg].l; \
|
||||
setflags ## 32 flagops; \
|
||||
regs[rm].l = operation; \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint32_t dst = geteal(); if (abrt) return 0; \
|
||||
uint32_t src = regs[reg].l; \
|
||||
seteal(operation); if (abrt) return 0; \
|
||||
setflags ## 32 flagops; \
|
||||
cycles -= timing_mrl; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
fetch_ea_32(fetchdat); \
|
||||
if (mod == 3) \
|
||||
{ \
|
||||
uint32_t dst = regs[rm].l; \
|
||||
uint32_t src = regs[reg].l; \
|
||||
setflags ## 32 flagops; \
|
||||
regs[rm].l = operation; \
|
||||
cycles -= timing_rr; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
uint32_t dst = geteal(); if (abrt) return 0; \
|
||||
uint32_t src = regs[reg].l; \
|
||||
seteal(operation); if (abrt) return 0; \
|
||||
setflags ## 32 flagops; \
|
||||
cycles -= timing_mrl; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _b_rm_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint8_t dst, src; \
|
||||
fetch_ea_16(fetchdat); \
|
||||
dst = getr8(reg); \
|
||||
src = geteab(); if (abrt) return 0; \
|
||||
setflags ## 8 flagops; \
|
||||
setr8(reg, operation); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _b_rm_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint8_t dst, src; \
|
||||
fetch_ea_32(fetchdat); \
|
||||
dst = getr8(reg); \
|
||||
src = geteab(); if (abrt) return 0; \
|
||||
setflags ## 8 flagops; \
|
||||
setr8(reg, operation); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _w_rm_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint16_t dst, src; \
|
||||
fetch_ea_16(fetchdat); \
|
||||
dst = regs[reg].w; \
|
||||
src = geteaw(); if (abrt) return 0; \
|
||||
setflags ## 16 flagops; \
|
||||
regs[reg].w = operation; \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _w_rm_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint16_t dst, src; \
|
||||
fetch_ea_32(fetchdat); \
|
||||
dst = regs[reg].w; \
|
||||
src = geteaw(); if (abrt) return 0; \
|
||||
setflags ## 16 flagops; \
|
||||
regs[reg].w = operation; \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _l_rm_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint32_t dst, src; \
|
||||
fetch_ea_16(fetchdat); \
|
||||
dst = regs[reg].l; \
|
||||
src = geteal(); if (abrt) return 0; \
|
||||
setflags ## 32 flagops; \
|
||||
regs[reg].l = operation; \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rml; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## name ## _l_rm_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint32_t dst, src; \
|
||||
fetch_ea_32(fetchdat); \
|
||||
dst = regs[reg].l; \
|
||||
src = geteal(); if (abrt) return 0; \
|
||||
setflags ## 32 flagops; \
|
||||
regs[reg].l = operation; \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rml; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _AL_imm(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint8_t dst = AL; \
|
||||
uint8_t src = getbytef(); \
|
||||
setflags ## 8 flagops; \
|
||||
AL = operation; \
|
||||
cycles -= timing_rr; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _AX_imm(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint16_t dst = AX; \
|
||||
uint16_t src = getwordf(); \
|
||||
setflags ## 16 flagops; \
|
||||
AX = operation; \
|
||||
cycles -= timing_rr; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int op ## name ## _EAX_imm(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc = CF_SET(); \
|
||||
uint32_t dst = EAX; \
|
||||
uint32_t src = getlong(); \
|
||||
setflags ## 32 flagops; \
|
||||
EAX = operation; \
|
||||
cycles -= timing_rr; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
OP_ARITH(ADD, dst + src, setadd, (dst, src))
|
||||
OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src))
|
||||
OP_ARITH(SUB, dst - src, setsub, (dst, src))
|
||||
OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src))
|
||||
OP_ARITH(OR, dst | src, setznp, (dst | src))
|
||||
OP_ARITH(AND, dst & src, setznp, (dst & src))
|
||||
OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src))
|
||||
|
||||
static int opCMP_b_rmw_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t dst;
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteab(); if (abrt) return 0;
|
||||
setsub8(dst, getr8(reg));
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_b_rmw_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t dst;
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteab(); if (abrt) return 0;
|
||||
setsub8(dst, getr8(reg));
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_w_rmw_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t dst;
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteaw(); if (abrt) return 0;
|
||||
setsub16(dst, regs[reg].w);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_w_rmw_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t dst;
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteaw(); if (abrt) return 0;
|
||||
setsub16(dst, regs[reg].w);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_l_rmw_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t dst;
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteal(); if (abrt) return 0;
|
||||
setsub32(dst, regs[reg].l);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_l_rmw_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t dst;
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteal(); if (abrt) return 0;
|
||||
setsub32(dst, regs[reg].l);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_b_rm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src;
|
||||
fetch_ea_16(fetchdat);
|
||||
src = geteab(); if (abrt) return 0;
|
||||
setsub8(getr8(reg), src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm;
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_b_rm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src;
|
||||
fetch_ea_32(fetchdat);
|
||||
src = geteab(); if (abrt) return 0;
|
||||
setsub8(getr8(reg), src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_w_rm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src;
|
||||
fetch_ea_16(fetchdat);
|
||||
src = geteaw(); if (abrt) return 0;
|
||||
setsub16(regs[reg].w, src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm;
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_w_rm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src;
|
||||
fetch_ea_32(fetchdat);
|
||||
src = geteaw(); if (abrt) return 0;
|
||||
setsub16(regs[reg].w, src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_l_rm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src;
|
||||
fetch_ea_16(fetchdat);
|
||||
src = geteal(); if (abrt) return 0;
|
||||
setsub32(regs[reg].l, src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rml;
|
||||
return 0;
|
||||
}
|
||||
static int opCMP_l_rm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src;
|
||||
fetch_ea_32(fetchdat);
|
||||
src = geteal(); if (abrt) return 0;
|
||||
setsub32(regs[reg].l, src);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_rml;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_AL_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src = getbytef();
|
||||
setsub8(AL, src);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_AX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src = getwordf();
|
||||
setsub16(AX, src);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMP_EAX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src = getlong();
|
||||
setsub32(EAX, src);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opTEST_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp, temp2;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
temp2 = getr8(reg);
|
||||
setznp8(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opTEST_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp, temp2;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
temp2 = getr8(reg);
|
||||
setznp8(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opTEST_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp, temp2;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
temp2 = regs[reg].w;
|
||||
setznp16(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opTEST_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp, temp2;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
temp2 = regs[reg].w;
|
||||
setznp16(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opTEST_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp, temp2;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
temp2 = regs[reg].l;
|
||||
setznp32(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opTEST_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp, temp2;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
temp2 = regs[reg].l;
|
||||
setznp32(temp & temp2);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opTEST_AL(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = getbytef();
|
||||
setznp8(AL & temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opTEST_AX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = getwordf();
|
||||
setznp16(AX & temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opTEST_EAX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = getlong(); if (abrt) return 0;
|
||||
setznp32(EAX & temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define ARITH_MULTI(ea_width, flag_width) \
|
||||
dst = getea ## ea_width(); if (abrt) return 0; \
|
||||
switch (rmdat&0x38) \
|
||||
{ \
|
||||
case 0x00: /*ADD ea, #*/ \
|
||||
setea ## ea_width(dst + src); if (abrt) return 0; \
|
||||
setadd ## flag_width(dst, src); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x08: /*OR ea, #*/ \
|
||||
dst |= src; \
|
||||
setea ## ea_width(dst); if (abrt) return 0; \
|
||||
setznp ## flag_width(dst); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x10: /*ADC ea, #*/ \
|
||||
setea ## ea_width(dst + src + tempc); if (abrt) return 0; \
|
||||
setadc ## flag_width(dst, src); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x18: /*SBB ea, #*/ \
|
||||
setea ## ea_width(dst - (src + tempc)); if (abrt) return 0; \
|
||||
setsbc ## flag_width(dst, src); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x20: /*AND ea, #*/ \
|
||||
dst &= src; \
|
||||
setea ## ea_width(dst); if (abrt) return 0; \
|
||||
setznp ## flag_width(dst); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x28: /*SUB ea, #*/ \
|
||||
setea ## ea_width(dst - src); if (abrt) return 0; \
|
||||
setsub ## flag_width(dst, src); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x30: /*XOR ea, #*/ \
|
||||
dst ^= src; \
|
||||
setea ## ea_width(dst); if (abrt) return 0; \
|
||||
setznp ## flag_width(dst); \
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mr; \
|
||||
break; \
|
||||
case 0x38: /*CMP ea, #*/ \
|
||||
setsub ## flag_width(dst, src); \
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2); \
|
||||
else cycles -= ((mod == 3) ? 2 : 7); \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
||||
static int op80_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
ARITH_MULTI(b, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op80_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
ARITH_MULTI(b, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op81_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
src = getword(); if (abrt) return 0;
|
||||
ARITH_MULTI(w, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op81_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
src = getword(); if (abrt) return 0;
|
||||
ARITH_MULTI(w, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op81_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
src = getlong(); if (abrt) return 0;
|
||||
ARITH_MULTI(l, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op81_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
src = getlong(); if (abrt) return 0;
|
||||
ARITH_MULTI(l, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op83_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
if (src & 0x80) src |= 0xff00;
|
||||
ARITH_MULTI(w, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op83_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
if (src & 0x80) src |= 0xff00;
|
||||
ARITH_MULTI(w, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op83_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
if (src & 0x80) src |= 0xffffff00;
|
||||
ARITH_MULTI(l, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int op83_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
src = getbyte(); if (abrt) return 0;
|
||||
if (src & 0x80) src |= 0xffffff00;
|
||||
ARITH_MULTI(l, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
209
src/x86_ops_atomic.h
Normal file
209
src/x86_ops_atomic.h
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
static int opCMPXCHG_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp, temp2 = AL;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
if (AL == temp) seteab(getr8(reg));
|
||||
else AL = temp;
|
||||
if (abrt) return 0;
|
||||
setsub8(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPXCHG_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp, temp2 = AL;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
if (AL == temp) seteab(getr8(reg));
|
||||
else AL = temp;
|
||||
if (abrt) return 0;
|
||||
setsub8(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMPXCHG_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp, temp2 = AX;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
if (AX == temp) seteaw(regs[reg].w);
|
||||
else AX = temp;
|
||||
if (abrt) return 0;
|
||||
setsub16(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPXCHG_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp, temp2 = AX;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
if (AX == temp) seteaw(regs[reg].w);
|
||||
else AX = temp;
|
||||
if (abrt) return 0;
|
||||
setsub16(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMPXCHG_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp, temp2 = EAX;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
if (EAX == temp) seteal(regs[reg].l);
|
||||
else EAX = temp;
|
||||
if (abrt) return 0;
|
||||
setsub32(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPXCHG_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp, temp2 = EAX;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
if (EAX == temp) seteal(regs[reg].l);
|
||||
else EAX = temp;
|
||||
if (abrt) return 0;
|
||||
setsub32(temp2, temp);
|
||||
cycles -= (mod == 3) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXADD_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
seteab(temp + getr8(reg)); if (abrt) return 0;
|
||||
setadd8(temp, getr8(reg));
|
||||
setr8(reg, temp);
|
||||
return 0;
|
||||
}
|
||||
static int opXADD_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
seteab(temp + getr8(reg)); if (abrt) return 0;
|
||||
setadd8(temp, getr8(reg));
|
||||
setr8(reg, temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXADD_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp + regs[reg].w); if (abrt) return 0;
|
||||
setadd16(temp, regs[reg].w);
|
||||
regs[reg].w = temp;
|
||||
return 0;
|
||||
}
|
||||
static int opXADD_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp + regs[reg].w); if (abrt) return 0;
|
||||
setadd16(temp, regs[reg].w);
|
||||
regs[reg].w = temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXADD_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp + regs[reg].l); if (abrt) return 0;
|
||||
setadd32(temp, regs[reg].l);
|
||||
regs[reg].l = temp;
|
||||
return 0;
|
||||
}
|
||||
static int opXADD_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
if (!is486)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp + regs[reg].l); if (abrt) return 0;
|
||||
setadd32(temp, regs[reg].l);
|
||||
regs[reg].l = temp;
|
||||
return 0;
|
||||
}
|
||||
105
src/x86_ops_bcd.h
Normal file
105
src/x86_ops_bcd.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
static int opAAA(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
if ((flags & A_FLAG) || ((AL & 0xF) > 9))
|
||||
{
|
||||
AL += 6;
|
||||
AH++;
|
||||
flags |= (A_FLAG | C_FLAG);
|
||||
}
|
||||
else
|
||||
flags &= ~(A_FLAG | C_FLAG);
|
||||
AL &= 0xF;
|
||||
cycles -= is486 ? 3 : 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opAAD(uint32_t fetchdat)
|
||||
{
|
||||
int base = getbytef();
|
||||
if (cpu_manufacturer != MANU_INTEL) base = 10;
|
||||
AL = (AH * base) + AL;
|
||||
AH = 0;
|
||||
setznp16(AX);
|
||||
cycles -= (is486) ? 14 : 19;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opAAM(uint32_t fetchdat)
|
||||
{
|
||||
int base = getbytef();
|
||||
if (!base || cpu_manufacturer != MANU_INTEL) base = 10;
|
||||
AH = AL / base;
|
||||
AL %= base;
|
||||
setznp16(AX);
|
||||
cycles -= (is486) ? 15 : 17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opAAS(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
if ((flags & A_FLAG) || ((AL & 0xF) > 9))
|
||||
{
|
||||
AL -= 6;
|
||||
AH--;
|
||||
flags |= (A_FLAG | C_FLAG);
|
||||
}
|
||||
else
|
||||
flags &= ~(A_FLAG | C_FLAG);
|
||||
AL &= 0xF;
|
||||
cycles -= is486 ? 3 : 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opDAA(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw;
|
||||
|
||||
flags_rebuild();
|
||||
if ((flags & A_FLAG) || ((AL & 0xf) > 9))
|
||||
{
|
||||
int tempi = ((uint16_t)AL) + 6;
|
||||
AL += 6;
|
||||
flags |= A_FLAG;
|
||||
if (tempi & 0x100) flags |= C_FLAG;
|
||||
}
|
||||
if ((flags & C_FLAG) || (AL > 0x9f))
|
||||
{
|
||||
AL += 0x60;
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
|
||||
tempw = flags & (C_FLAG | A_FLAG);
|
||||
setznp8(AL);
|
||||
flags |= tempw;
|
||||
cycles -= 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opDAS(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw;
|
||||
|
||||
flags_rebuild();
|
||||
if ((flags & A_FLAG) || ((AL & 0xf) > 9))
|
||||
{
|
||||
int tempi = ((uint16_t)AL) - 6;
|
||||
AL -= 6;
|
||||
flags |= A_FLAG;
|
||||
if (tempi & 0x100) flags |= C_FLAG;
|
||||
}
|
||||
if ((flags & C_FLAG) || (AL > 0x9f))
|
||||
{
|
||||
AL -= 0x60;
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
|
||||
tempw = flags & (C_FLAG | A_FLAG);
|
||||
setznp8(AL);
|
||||
flags |= tempw;
|
||||
cycles -= 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
297
src/x86_ops_bit.h
Normal file
297
src/x86_ops_bit.h
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
static int opBT_w_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
int tempc;
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
eaaddr += ((regs[reg].w / 16) * 2); eal_r = 0;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
if (temp & (1 << (regs[reg].w & 15))) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opBT_w_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
eaaddr += ((regs[reg].w / 16) * 2); eal_r = 0;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
if (temp & (1 << (regs[reg].w & 15))) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opBT_l_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
eaaddr += ((regs[reg].l / 32) * 4); eal_r = 0;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
if (temp & (1 << (regs[reg].l & 31))) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opBT_l_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
eaaddr += ((regs[reg].l / 32) * 4); eal_r = 0;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
if (temp & (1 << (regs[reg].l & 31))) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define opBT(name, operation) \
|
||||
static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc; \
|
||||
uint16_t temp; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
eaaddr += ((regs[reg].w / 16) * 2); eal_r = eal_w = 0; \
|
||||
temp = geteaw(); if (abrt) return 0; \
|
||||
tempc = (temp & (1 << (regs[reg].w & 15))) ? 1 : 0; \
|
||||
temp operation (1 << (regs[reg].w & 15)); \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
else flags &= ~C_FLAG; \
|
||||
\
|
||||
cycles -= 6; \
|
||||
return 0; \
|
||||
} \
|
||||
static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc; \
|
||||
uint16_t temp; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
eaaddr += ((regs[reg].w / 16) * 2); eal_r = eal_w = 0; \
|
||||
temp = geteaw(); if (abrt) return 0; \
|
||||
tempc = (temp & (1 << (regs[reg].w & 15))) ? 1 : 0; \
|
||||
temp operation (1 << (regs[reg].w & 15)); \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
else flags &= ~C_FLAG; \
|
||||
\
|
||||
cycles -= 6; \
|
||||
return 0; \
|
||||
} \
|
||||
static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc; \
|
||||
uint32_t temp; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
eaaddr += ((regs[reg].l / 32) * 4); eal_r = eal_w = 0; \
|
||||
temp = geteal(); if (abrt) return 0; \
|
||||
tempc = (temp & (1 << (regs[reg].l & 31))) ? 1 : 0; \
|
||||
temp operation (1 << (regs[reg].l & 31)); \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
else flags &= ~C_FLAG; \
|
||||
\
|
||||
cycles -= 6; \
|
||||
return 0; \
|
||||
} \
|
||||
static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int tempc; \
|
||||
uint32_t temp; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
eaaddr += ((regs[reg].l / 32) * 4); eal_r = eal_w = 0; \
|
||||
temp = geteal(); if (abrt) return 0; \
|
||||
tempc = (temp & (1 << (regs[reg].l & 31))) ? 1 : 0; \
|
||||
temp operation (1 << (regs[reg].l & 31)); \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
else flags &= ~C_FLAG; \
|
||||
\
|
||||
cycles -= 6; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opBT(C, ^=)
|
||||
opBT(R, &=~)
|
||||
opBT(S, |=)
|
||||
|
||||
static int opBA_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int tempc, count;
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
temp = geteaw();
|
||||
count = getbyte(); if (abrt) return 0;
|
||||
tempc = temp & (1 << count);
|
||||
flags_rebuild();
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x20: /*BT w,imm*/
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
case 0x28: /*BTS w,imm*/
|
||||
temp |= (1 << count);
|
||||
break;
|
||||
case 0x30: /*BTR w,imm*/
|
||||
temp &= ~(1 << count);
|
||||
break;
|
||||
case 0x38: /*BTC w,imm*/
|
||||
temp ^= (1 << count);
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
seteaw(temp); if (abrt) return 0;
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opBA_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int tempc, count;
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
temp = geteaw();
|
||||
count = getbyte(); if (abrt) return 0;
|
||||
tempc = temp & (1 << count);
|
||||
flags_rebuild();
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x20: /*BT w,imm*/
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
case 0x28: /*BTS w,imm*/
|
||||
temp |= (1 << count);
|
||||
break;
|
||||
case 0x30: /*BTR w,imm*/
|
||||
temp &= ~(1 << count);
|
||||
break;
|
||||
case 0x38: /*BTC w,imm*/
|
||||
temp ^= (1 << count);
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
seteaw(temp); if (abrt) return 0;
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opBA_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int tempc, count;
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
temp = geteal();
|
||||
count = getbyte(); if (abrt) return 0;
|
||||
tempc = temp & (1 << count);
|
||||
flags_rebuild();
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x20: /*BT w,imm*/
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
case 0x28: /*BTS w,imm*/
|
||||
temp |= (1 << count);
|
||||
break;
|
||||
case 0x30: /*BTR w,imm*/
|
||||
temp &= ~(1 << count);
|
||||
break;
|
||||
case 0x38: /*BTC w,imm*/
|
||||
temp ^= (1 << count);
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
seteal(temp); if (abrt) return 0;
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opBA_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int tempc, count;
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
temp = geteal();
|
||||
count = getbyte(); if (abrt) return 0;
|
||||
tempc = temp & (1 << count);
|
||||
flags_rebuild();
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x20: /*BT w,imm*/
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
case 0x28: /*BTS w,imm*/
|
||||
temp |= (1 << count);
|
||||
break;
|
||||
case 0x30: /*BTR w,imm*/
|
||||
temp &= ~(1 << count);
|
||||
break;
|
||||
case 0x38: /*BTC w,imm*/
|
||||
temp ^= (1 << count);
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
seteal(temp); if (abrt) return 0;
|
||||
if (tempc) flags |= C_FLAG;
|
||||
else flags &= ~C_FLAG;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
117
src/x86_ops_bitscan.h
Normal file
117
src/x86_ops_bitscan.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#define BS_common(start, end, dir, dest, time) \
|
||||
flags_rebuild(); \
|
||||
if (temp) \
|
||||
{ \
|
||||
int c; \
|
||||
flags &= ~Z_FLAG; \
|
||||
for (c = start; c != end; c += dir) \
|
||||
{ \
|
||||
cycles -= time; \
|
||||
if (temp & (1 << c)) \
|
||||
{ \
|
||||
dest = c; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
flags |= Z_FLAG;
|
||||
|
||||
static int opBSF_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
|
||||
BS_common(0, 16, 1, regs[reg].w, (is486) ? 1 : 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSF_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
|
||||
BS_common(0, 16, 1, regs[reg].w, (is486) ? 1 : 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSF_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
|
||||
BS_common(0, 32, 1, regs[reg].l, (is486) ? 1 : 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSF_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
|
||||
BS_common(0, 32, 1, regs[reg].l, (is486) ? 1 : 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opBSR_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
|
||||
BS_common(15, -1, -1, regs[reg].w, 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSR_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
|
||||
BS_common(15, -1, -1, regs[reg].w, 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSR_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
|
||||
BS_common(31, -1, -1, regs[reg].l, 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBSR_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
|
||||
BS_common(31, -1, -1, regs[reg].l, 3);
|
||||
|
||||
cycles -= (is486) ? 6 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
366
src/x86_ops_call.h
Normal file
366
src/x86_ops_call.h
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
#define CALL_FAR_w(new_seg, new_pc) \
|
||||
old_cs = CS; \
|
||||
old_pc = pc; \
|
||||
if (ssegs) ss = oldss; \
|
||||
oxpc = pc; \
|
||||
pc = new_pc; \
|
||||
optype = CALL; \
|
||||
cgate16 = cgate32 = 0; \
|
||||
if (msw & 1) loadcscall(new_seg); \
|
||||
else loadcs(new_seg); \
|
||||
optype = 0; \
|
||||
if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
oldss = ss; \
|
||||
if (cgate32) \
|
||||
{ \
|
||||
PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
PUSH_L(old_pc); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
PUSH_W(old_pc); \
|
||||
}
|
||||
|
||||
#define CALL_FAR_l(new_seg, new_pc) \
|
||||
old_cs = CS; \
|
||||
old_pc = pc; \
|
||||
if (ssegs) ss = oldss; \
|
||||
oxpc = pc; \
|
||||
pc = new_pc; \
|
||||
optype = CALL; \
|
||||
cgate16 = cgate32 = 0; \
|
||||
if (msw & 1) loadcscall(new_seg); \
|
||||
else loadcs(new_seg); \
|
||||
optype = 0; \
|
||||
if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
oldss = ss; \
|
||||
if (cgate16) \
|
||||
{ \
|
||||
PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
PUSH_W(old_pc); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
|
||||
PUSH_L(old_pc); \
|
||||
}
|
||||
|
||||
|
||||
#define CALL_FAR_nr(new_seg, new_pc) \
|
||||
old_cs = CS; \
|
||||
old_pc = pc; \
|
||||
if (ssegs) ss = oldss; \
|
||||
oxpc = pc; \
|
||||
pc = new_pc; \
|
||||
optype = CALL; \
|
||||
cgate16 = cgate32 = 0; \
|
||||
if (msw & 1) loadcscall(new_seg); \
|
||||
else loadcs(new_seg); \
|
||||
optype = 0; \
|
||||
if (abrt) { cgate16 = cgate32 = 0; break; } \
|
||||
oldss = ss; \
|
||||
if (cgate32) \
|
||||
{ \
|
||||
PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \
|
||||
PUSH_L(old_pc); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \
|
||||
PUSH_W(old_pc); \
|
||||
} \
|
||||
|
||||
static int opCALL_far_w(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t old_cs, old_pc;
|
||||
uint16_t new_cs, new_pc;
|
||||
|
||||
new_pc = getwordf();
|
||||
new_cs = getword(); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_w(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 18 : 17;
|
||||
return 0;
|
||||
}
|
||||
static int opCALL_far_l(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t old_cs, old_pc;
|
||||
uint32_t new_cs, new_pc;
|
||||
|
||||
new_pc = getlong();
|
||||
new_cs = getword(); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_l(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 18 : 17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opFF_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t old_cs, new_cs;
|
||||
uint32_t old_pc, new_pc;
|
||||
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*INC w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp + 1); if (abrt) return 0;
|
||||
setadd16nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x08: /*DEC w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp - 1); if (abrt) return 0;
|
||||
setsub16nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x10: /*CALL*/
|
||||
new_pc = geteaw(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_W(pc);
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x18: /*CALL far*/
|
||||
new_pc = readmemw(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_w(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 17 : 22;
|
||||
break;
|
||||
case 0x20: /*JMP*/
|
||||
new_pc = geteaw(); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x28: /*JMP far*/
|
||||
oxpc = pc;
|
||||
new_pc = readmemw(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
loadcsjmp(new_cs, oxpc); if (abrt) return 0;
|
||||
cycles -= is486 ? 13 : 12;
|
||||
break;
|
||||
case 0x30: /*PUSH w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_W(temp);
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Bad FF opcode %02X\n",rmdat&0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opFF_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t old_cs, new_cs;
|
||||
uint32_t old_pc, new_pc;
|
||||
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*INC w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp + 1); if (abrt) return 0;
|
||||
setadd16nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x08: /*DEC w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(temp - 1); if (abrt) return 0;
|
||||
setsub16nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x10: /*CALL*/
|
||||
new_pc = geteaw(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_W(pc);
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x18: /*CALL far*/
|
||||
new_pc = readmemw(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_w(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 17 : 22;
|
||||
break;
|
||||
case 0x20: /*JMP*/
|
||||
new_pc = geteaw(); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x28: /*JMP far*/
|
||||
oxpc = pc;
|
||||
new_pc = readmemw(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
loadcsjmp(new_cs, oxpc); if (abrt) return 0;
|
||||
cycles -= is486 ? 13 : 12;
|
||||
break;
|
||||
case 0x30: /*PUSH w*/
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_W(temp);
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Bad FF opcode %02X\n",rmdat&0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opFF_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t old_cs, new_cs;
|
||||
uint32_t old_pc, new_pc;
|
||||
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*INC l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp + 1); if (abrt) return 0;
|
||||
setadd32nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x08: /*DEC l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp - 1); if (abrt) return 0;
|
||||
setsub32nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x10: /*CALL*/
|
||||
new_pc = geteal(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_L(pc);
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x18: /*CALL far*/
|
||||
new_pc = readmeml(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_l(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 17 : 22;
|
||||
break;
|
||||
case 0x20: /*JMP*/
|
||||
new_pc = geteal(); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x28: /*JMP far*/
|
||||
oxpc = pc;
|
||||
new_pc = readmeml(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
loadcsjmp(new_cs, oxpc); if (abrt) return 0;
|
||||
cycles -= is486 ? 13 : 12;
|
||||
break;
|
||||
case 0x30: /*PUSH l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_L(temp);
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Bad FF opcode %02X\n",rmdat&0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opFF_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t old_cs, new_cs;
|
||||
uint32_t old_pc, new_pc;
|
||||
|
||||
uint32_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*INC l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp + 1); if (abrt) return 0;
|
||||
setadd32nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x08: /*DEC l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(temp - 1); if (abrt) return 0;
|
||||
setsub32nc(temp, 1);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x10: /*CALL*/
|
||||
new_pc = geteal(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_L(pc); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x18: /*CALL far*/
|
||||
new_pc = readmeml(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0;
|
||||
|
||||
CALL_FAR_l(new_cs, new_pc);
|
||||
|
||||
cycles -= is486 ? 17 : 22;
|
||||
break;
|
||||
case 0x20: /*JMP*/
|
||||
new_pc = geteal(); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
if (is486) cycles -= 5;
|
||||
else cycles -= ((mod == 3) ? 7 : 10);
|
||||
break;
|
||||
case 0x28: /*JMP far*/
|
||||
oxpc = pc;
|
||||
new_pc = readmeml(easeg, eaaddr);
|
||||
new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
pc = new_pc;
|
||||
loadcsjmp(new_cs, oxpc); if (abrt) return 0;
|
||||
cycles -= is486 ? 13 : 12;
|
||||
break;
|
||||
case 0x30: /*PUSH l*/
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
if (ssegs) ss = oldss;
|
||||
PUSH_L(temp);
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Bad FF opcode %02X\n",rmdat&0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
178
src/x86_ops_flag.h
Normal file
178
src/x86_ops_flag.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
static int opCMC(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags ^= C_FLAG;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opCLC(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags &= ~C_FLAG;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opCLD(uint32_t fetchdat)
|
||||
{
|
||||
flags &= ~D_FLAG;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opCLI(uint32_t fetchdat)
|
||||
{
|
||||
if (!IOPLp)
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
}
|
||||
else
|
||||
flags &= ~I_FLAG;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSTC(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags |= C_FLAG;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opSTD(uint32_t fetchdat)
|
||||
{
|
||||
flags |= D_FLAG;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opSTI(uint32_t fetchdat)
|
||||
{
|
||||
if (!IOPLp)
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
}
|
||||
else
|
||||
flags |= I_FLAG;
|
||||
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSAHF(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags = (flags & 0xff00) | (AH & 0xd5) | 2;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opLAHF(uint32_t fetchdat)
|
||||
{
|
||||
flags_rebuild();
|
||||
AH = flags & 0xff;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPUSHF(uint32_t fetchdat)
|
||||
{
|
||||
if (ssegs) ss = oldss;
|
||||
if ((eflags & VM_FLAG) && (IOPL < 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
flags_rebuild();
|
||||
PUSH_W(flags);
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
static int opPUSHFD(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw;
|
||||
if (ssegs) ss=oldss;
|
||||
if ((eflags & VM_FLAG) && (IOPL < 3))
|
||||
{
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
if (CPUID) tempw = eflags & 0x24;
|
||||
else tempw = eflags & 4;
|
||||
flags_rebuild();
|
||||
PUSH_L(flags | (tempw << 16));
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPOPF_286(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw;
|
||||
if (ssegs) ss = oldss;
|
||||
|
||||
if ((eflags & VM_FLAG) && (IOPL < 3))
|
||||
{
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tempw = POP_W(); if (abrt) return 0;
|
||||
|
||||
pclog("POPF_286 %04X:%04X %04X\n", CS, pc, tempw);
|
||||
if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2;
|
||||
else if (!(CPL)) flags = (tempw & 0x7fd5) | 2;
|
||||
else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2;
|
||||
else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2;
|
||||
flags_extract();
|
||||
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opPOPF(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw;
|
||||
if (ssegs) ss = oldss;
|
||||
|
||||
if ((eflags & VM_FLAG) && (IOPL < 3))
|
||||
{
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tempw = POP_W(); if (abrt) return 0;
|
||||
|
||||
if (!(CPL) || !(msw & 1)) flags = (tempw & 0xffd5) | 2;
|
||||
else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0xcfd5) | 2;
|
||||
else flags = (flags & 0x3200) | (tempw & 0xcdd5) | 2;
|
||||
flags_extract();
|
||||
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opPOPFD(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ;
|
||||
if (ssegs) ss = oldss;
|
||||
|
||||
if ((eflags & VM_FLAG) && (IOPL < 3))
|
||||
{
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
templ = POP_L(); if (abrt) return 0;
|
||||
|
||||
if (!(CPL) || !(msw & 1)) flags = (templ & 0xffd5) | 2;
|
||||
else if (IOPLp) flags = (flags & 0x3000) | (templ & 0xcfd5) | 2;
|
||||
else flags = (flags & 0x3200) | (templ & 0xcdd5) | 2;
|
||||
|
||||
templ &= is486 ? 0x240000 : 0;
|
||||
templ |= ((eflags&3) << 16);
|
||||
if (CPUID) eflags = (templ >> 16) & 0x27;
|
||||
else if (is486) eflags = (templ >> 16) & 7;
|
||||
else eflags = (templ >> 16) & 3;
|
||||
|
||||
flags_extract();
|
||||
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
60
src/x86_ops_fpu.h
Normal file
60
src/x86_ops_fpu.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#define opESCAPE(num) \
|
||||
static int opESCAPE_ ## num ##_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
flags_rebuild(); \
|
||||
if ((cr0 & 6) == 4) \
|
||||
{ \
|
||||
x86_int(7); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fpucount++; \
|
||||
fetch_ea_16(fetchdat); \
|
||||
if (hasfpu) \
|
||||
{ \
|
||||
x87_pc_off = oldpc; \
|
||||
x87_pc_seg = CS; \
|
||||
x87_op_off = eaaddr; \
|
||||
x87_op_seg = ea_rseg; \
|
||||
x87_ ## num(); \
|
||||
} \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
static int opESCAPE_ ## num ## _a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
flags_rebuild(); \
|
||||
if ((cr0 & 6) == 4) \
|
||||
{ \
|
||||
x86_int(7); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fpucount++; \
|
||||
fetch_ea_32(fetchdat); \
|
||||
if (hasfpu) \
|
||||
{ \
|
||||
x87_pc_off = oldpc; \
|
||||
x87_pc_seg = CS; \
|
||||
x87_op_off = eaaddr; \
|
||||
x87_op_seg = ea_rseg; \
|
||||
x87_ ## num(); \
|
||||
} \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opESCAPE(d8);
|
||||
opESCAPE(d9);
|
||||
opESCAPE(da);
|
||||
opESCAPE(db);
|
||||
opESCAPE(dc);
|
||||
opESCAPE(dd);
|
||||
opESCAPE(de);
|
||||
opESCAPE(df);
|
||||
|
||||
static int opWAIT(uint32_t fetchdat)
|
||||
{
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
86
src/x86_ops_inc_dec.h
Normal file
86
src/x86_ops_inc_dec.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#define INC_DEC_OP(name, reg, inc, setflags) \
|
||||
static int op ## name (uint32_t fetchdat) \
|
||||
{ \
|
||||
setflags(reg, 1); \
|
||||
reg += inc; \
|
||||
cycles -= timing_rr; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
INC_DEC_OP(INC_AX, AX, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_BX, BX, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_CX, CX, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_DX, DX, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_SI, SI, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_DI, DI, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_BP, BP, 1, setadd16nc)
|
||||
INC_DEC_OP(INC_SP, SP, 1, setadd16nc)
|
||||
|
||||
INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc)
|
||||
INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc)
|
||||
|
||||
INC_DEC_OP(DEC_AX, AX, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_BX, BX, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_CX, CX, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_DX, DX, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_SI, SI, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_DI, DI, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_BP, BP, -1, setsub16nc)
|
||||
INC_DEC_OP(DEC_SP, SP, -1, setsub16nc)
|
||||
|
||||
INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc)
|
||||
INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc)
|
||||
|
||||
|
||||
static int opINCDEC_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp=geteab(); if (abrt) return 0;
|
||||
|
||||
if (rmdat&0x38)
|
||||
{
|
||||
seteab(temp - 1); if (abrt) return 0;
|
||||
setsub8nc(temp, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
seteab(temp + 1); if (abrt) return 0;
|
||||
setadd8nc(temp, 1);
|
||||
}
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
return 0;
|
||||
}
|
||||
static int opINCDEC_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp=geteab(); if (abrt) return 0;
|
||||
|
||||
if (rmdat&0x38)
|
||||
{
|
||||
seteab(temp - 1); if (abrt) return 0;
|
||||
setsub8nc(temp, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
seteab(temp + 1); if (abrt) return 0;
|
||||
setadd8nc(temp, 1);
|
||||
}
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
return 0;
|
||||
}
|
||||
46
src/x86_ops_int.h
Normal file
46
src/x86_ops_int.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
static int opINT3(uint32_t fetchdat)
|
||||
{
|
||||
oldpc = pc;
|
||||
//fatal("INT3\n");
|
||||
if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
x86_int_sw(3);
|
||||
cycles -= (is486) ? 44 : 59;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINT(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
/*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/
|
||||
if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
temp = getbytef();
|
||||
if (temp == 0x10 && AH == 0xe) pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc);
|
||||
x86_int_sw(temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINTO(uint32_t fetchdat)
|
||||
{
|
||||
if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
if (VF_SET())
|
||||
{
|
||||
oldpc = pc;
|
||||
x86_int_sw(4);
|
||||
}
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
110
src/x86_ops_io.h
Normal file
110
src/x86_ops_io.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
int opIN_AL_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
AL = inb(port);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
int opIN_AX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
check_io_perm(port + 1);
|
||||
AX = inw(port);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
int opIN_EAX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
check_io_perm(port + 1);
|
||||
check_io_perm(port + 2);
|
||||
check_io_perm(port + 3);
|
||||
EAX = inl(port);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opOUT_AL_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
outb(port, AL);
|
||||
cycles -= 10;
|
||||
return 0;
|
||||
}
|
||||
int opOUT_AX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
check_io_perm(port + 1);
|
||||
outw(port, AX);
|
||||
cycles -= 10;
|
||||
return 0;
|
||||
}
|
||||
int opOUT_EAX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t port = (uint16_t)getbytef();
|
||||
check_io_perm(port);
|
||||
check_io_perm(port + 1);
|
||||
check_io_perm(port + 2);
|
||||
check_io_perm(port + 3);
|
||||
outl(port, EAX);
|
||||
cycles -= 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opIN_AL_DX(uint32_t fetchdat)
|
||||
{
|
||||
check_io_perm(DX);
|
||||
AL = inb(DX);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
int opIN_AX_DX(uint32_t fetchdat)
|
||||
{
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
AX = inw(DX);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
int opIN_EAX_DX(uint32_t fetchdat)
|
||||
{
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
EAX = inl(DX);
|
||||
cycles -= 12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opOUT_AL_DX(uint32_t fetchdat)
|
||||
{
|
||||
check_io_perm(DX);
|
||||
outb(DX, AL);
|
||||
cycles -= 11;
|
||||
return 0;
|
||||
}
|
||||
int opOUT_AX_DX(uint32_t fetchdat)
|
||||
{
|
||||
//pclog("OUT_AX_DX %04X %04X\n", DX, AX);
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
outw(DX, AX);
|
||||
cycles -= 11;
|
||||
return 0;
|
||||
}
|
||||
int opOUT_EAX_DX(uint32_t fetchdat)
|
||||
{
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
outl(DX, EAX);
|
||||
cycles -= 11;
|
||||
return 0;
|
||||
}
|
||||
268
src/x86_ops_jump.h
Normal file
268
src/x86_ops_jump.h
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
#define cond_O ( VF_SET())
|
||||
#define cond_NO (!VF_SET())
|
||||
#define cond_B ( CF_SET())
|
||||
#define cond_NB (!CF_SET())
|
||||
#define cond_E ( ZF_SET())
|
||||
#define cond_NE (!ZF_SET())
|
||||
#define cond_BE ( CF_SET() || ZF_SET())
|
||||
#define cond_NBE (!CF_SET() && !ZF_SET())
|
||||
#define cond_S ( NF_SET())
|
||||
#define cond_NS (!NF_SET())
|
||||
#define cond_P ( PF_SET())
|
||||
#define cond_NP (!PF_SET())
|
||||
#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0))
|
||||
#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0))
|
||||
#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET()))
|
||||
#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET()))
|
||||
|
||||
#define opJ(condition) \
|
||||
static int opJ ## condition(uint32_t fetchdat) \
|
||||
{ \
|
||||
int8_t offset = (int8_t)getbytef(); \
|
||||
if (cond_ ## condition) \
|
||||
{ \
|
||||
pc += offset; \
|
||||
cycles -= timing_bt; \
|
||||
} \
|
||||
cycles -= timing_bnt; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opJ ## condition ## _w(uint32_t fetchdat) \
|
||||
{ \
|
||||
int16_t offset = (int16_t)getwordf(); \
|
||||
if (cond_ ## condition) \
|
||||
{ \
|
||||
pc += offset; \
|
||||
cycles -= timing_bt; \
|
||||
} \
|
||||
cycles -= timing_bnt; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opJ ## condition ## _l(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint32_t offset = getlong(); \
|
||||
if (cond_ ## condition) \
|
||||
{ \
|
||||
pc += offset; \
|
||||
cycles -= timing_bt; \
|
||||
} \
|
||||
cycles -= timing_bnt; \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
opJ(O)
|
||||
opJ(NO)
|
||||
opJ(B)
|
||||
opJ(NB)
|
||||
opJ(E)
|
||||
opJ(NE)
|
||||
opJ(BE)
|
||||
opJ(NBE)
|
||||
opJ(S)
|
||||
opJ(NS)
|
||||
opJ(P)
|
||||
opJ(NP)
|
||||
opJ(L)
|
||||
opJ(NL)
|
||||
opJ(LE)
|
||||
opJ(NLE)
|
||||
|
||||
|
||||
|
||||
static int opLOOPNE_w(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
CX--;
|
||||
if (CX && !ZF_SET())
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
static int opLOOPNE_l(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
ECX--;
|
||||
if (ECX && !ZF_SET())
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLOOPE_w(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
CX--;
|
||||
if (CX && ZF_SET())
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
static int opLOOPE_l(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
ECX--;
|
||||
if (ECX && ZF_SET())
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLOOP_w(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
CX--;
|
||||
if (CX)
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
static int opLOOP_l(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
ECX--;
|
||||
if (ECX)
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 7 : 11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opJCXZ(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
if (!CX)
|
||||
{
|
||||
pc += offset;
|
||||
cycles -= 4;
|
||||
}
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opJECXZ(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
if (!ECX)
|
||||
{
|
||||
pc += offset;
|
||||
cycles -= 4;
|
||||
}
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opJMP_r8(uint32_t fetchdat)
|
||||
{
|
||||
int8_t offset = (int8_t)getbytef();
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 3 : 7;
|
||||
return 0;
|
||||
}
|
||||
static int opJMP_r16(uint32_t fetchdat)
|
||||
{
|
||||
int16_t offset = (int16_t)getwordf();
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 3 : 7;
|
||||
return 0;
|
||||
}
|
||||
static int opJMP_r32(uint32_t fetchdat)
|
||||
{
|
||||
int32_t offset = (int32_t)getlong(); if (abrt) return 0;
|
||||
pc += offset;
|
||||
cycles -= (is486) ? 3 : 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opJMP_far_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
uint16_t seg = getword(); if (abrt) return 0;
|
||||
uint32_t oxpc = pc;
|
||||
pc = addr;
|
||||
loadcsjmp(seg, oxpc);
|
||||
cycles -= (is486) ? 17 : 12;
|
||||
return 0;
|
||||
}
|
||||
static int opJMP_far_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
uint16_t seg = getword(); if (abrt) return 0;
|
||||
uint32_t oxpc = pc;
|
||||
pc = addr;
|
||||
loadcsjmp(seg, oxpc);
|
||||
cycles -= (is486) ? 17 : 12;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opCALL_r16(uint32_t fetchdat)
|
||||
{
|
||||
int16_t addr = (int16_t)getwordf();
|
||||
if (ssegs) ss=oldss;
|
||||
PUSH_W(pc);
|
||||
pc += addr;
|
||||
cycles -= (is486) ? 3 : 7;
|
||||
return 0;
|
||||
}
|
||||
int opCALL_r32(uint32_t fetchdat)
|
||||
{
|
||||
int32_t addr = getlong(); if (abrt) return 0;
|
||||
if (ssegs) ss=oldss;
|
||||
PUSH_L(pc);
|
||||
pc += addr;
|
||||
cycles -= (is486) ? 3 : 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opRET_w(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
ret = POP_W(); if (abrt) return 0;
|
||||
pc = ret;
|
||||
|
||||
cycles -= (is486) ? 5 : 10;
|
||||
return 0;
|
||||
}
|
||||
int opRET_l(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
ret = POP_L(); if (abrt) return 0;
|
||||
pc = ret;
|
||||
|
||||
cycles -= (is486) ? 5 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opRET_w_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
uint16_t ret;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
ret = POP_W(); if (abrt) return 0;
|
||||
if (stack32) ESP += offset;
|
||||
else SP += offset;
|
||||
pc = ret;
|
||||
|
||||
cycles -= (is486) ? 5 : 10;
|
||||
return 0;
|
||||
}
|
||||
int opRET_l_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
uint32_t ret;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
ret = POP_L(); if (abrt) return 0;
|
||||
if (stack32) ESP += offset;
|
||||
else SP += offset;
|
||||
pc = ret;
|
||||
|
||||
cycles -= (is486) ? 5 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
678
src/x86_ops_misc.h
Normal file
678
src/x86_ops_misc.h
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
static int opCBW(uint32_t fetchdat)
|
||||
{
|
||||
AH = (AL & 0x80) ? 0xff : 0;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opCWDE(uint32_t fetchdat)
|
||||
{
|
||||
EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opCWD(uint32_t fetchdat)
|
||||
{
|
||||
DX = (AX & 0x8000) ? 0xFFFF : 0;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opCDQ(uint32_t fetchdat)
|
||||
{
|
||||
EDX = (EAX & 0x80000000) ? 0xffffffff : 0;
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opNOP(uint32_t fetchdat)
|
||||
{
|
||||
cycles -= (is486) ? 1 : 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSETALC(uint32_t fetchdat)
|
||||
{
|
||||
AL = (CF_SET()) ? 0xff : 0;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int opF6_a16(uint32_t fetchdat)
|
||||
{
|
||||
int tempws, tempws2;
|
||||
uint16_t tempw, src16;
|
||||
uint8_t src, dst;
|
||||
int8_t temps;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteab(); if (abrt) return 0;
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST b,#8*/
|
||||
src = readmemb(cs, pc); pc++; if (abrt) return 0;
|
||||
setznp8(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT b*/
|
||||
seteab(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x18: /*NEG b*/
|
||||
setsub8(0, dst);
|
||||
seteab(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x20: /*MUL AL,b*/
|
||||
AX = AL * dst;
|
||||
flags_rebuild();
|
||||
if (AH) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 13;
|
||||
break;
|
||||
case 0x28: /*IMUL AL,b*/
|
||||
tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
|
||||
AX = tempws & 0xffff;
|
||||
flags_rebuild();
|
||||
if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 14;
|
||||
break;
|
||||
case 0x30: /*DIV AL,b*/
|
||||
src16 = AX;
|
||||
if (dst) tempw = src16 / dst;
|
||||
if (dst && !(tempw & 0xff00))
|
||||
{
|
||||
AH = src16 % dst;
|
||||
AL = (src16 / dst) &0xff;
|
||||
if (!cpu_iscyrix)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags |= 0x8D5; /*Not a Cyrix*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= is486 ? 16 : 14;
|
||||
break;
|
||||
case 0x38: /*IDIV AL,b*/
|
||||
tempws = (int)(int16_t)AX;
|
||||
if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
|
||||
temps = tempws2 & 0xff;
|
||||
if (dst && ((int)temps == tempws2))
|
||||
{
|
||||
AH = (tempws % (int)((int8_t)dst)) & 0xff;
|
||||
AL = tempws2 & 0xff;
|
||||
if (!cpu_iscyrix)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags|=0x8D5; /*Not a Cyrix*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= 19;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F6 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opF6_a32(uint32_t fetchdat)
|
||||
{
|
||||
int tempws, tempws2;
|
||||
uint16_t tempw, src16;
|
||||
uint8_t src, dst;
|
||||
int8_t temps;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteab(); if (abrt) return 0;
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST b,#8*/
|
||||
src = readmemb(cs, pc); pc++; if (abrt) return 0;
|
||||
setznp8(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT b*/
|
||||
seteab(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x18: /*NEG b*/
|
||||
setsub8(0, dst);
|
||||
seteab(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x20: /*MUL AL,b*/
|
||||
AX = AL * dst;
|
||||
flags_rebuild();
|
||||
if (AH) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 13;
|
||||
break;
|
||||
case 0x28: /*IMUL AL,b*/
|
||||
tempws = (int)((int8_t)AL) * (int)((int8_t)dst);
|
||||
AX = tempws & 0xffff;
|
||||
flags_rebuild();
|
||||
if (AH && AH != 0xff) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 14;
|
||||
break;
|
||||
case 0x30: /*DIV AL,b*/
|
||||
src16 = AX;
|
||||
if (dst) tempw = src16 / dst;
|
||||
if (dst && !(tempw & 0xff00))
|
||||
{
|
||||
AH = src16 % dst;
|
||||
AL = (src16 / dst) &0xff;
|
||||
if (!cpu_iscyrix)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags |= 0x8D5; /*Not a Cyrix*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= is486 ? 16 : 14;
|
||||
break;
|
||||
case 0x38: /*IDIV AL,b*/
|
||||
tempws = (int)(int16_t)AX;
|
||||
if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
|
||||
temps = tempws2 & 0xff;
|
||||
if (dst && ((int)temps == tempws2))
|
||||
{
|
||||
AH = (tempws % (int)((int8_t)dst)) & 0xff;
|
||||
AL = tempws2 & 0xff;
|
||||
if (!cpu_iscyrix)
|
||||
{
|
||||
flags_rebuild();
|
||||
flags|=0x8D5; /*Not a Cyrix*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= 19;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F6 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int opF7_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ, templ2;
|
||||
int tempws, tempws2;
|
||||
int16_t temps16;
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteaw(); if (abrt) return 0;
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST w*/
|
||||
src = getword(); if (abrt) return 0;
|
||||
setznp16(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT w*/
|
||||
seteaw(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x18: /*NEG w*/
|
||||
setsub16(0, dst);
|
||||
seteaw(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x20: /*MUL AX,w*/
|
||||
templ = AX * dst;
|
||||
AX = templ & 0xFFFF;
|
||||
DX = templ >> 16;
|
||||
flags_rebuild();
|
||||
if (DX) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 21;
|
||||
break;
|
||||
case 0x28: /*IMUL AX,w*/
|
||||
templ = (int)((int16_t)AX) * (int)((int16_t)dst);
|
||||
AX = templ & 0xFFFF;
|
||||
DX = templ >> 16;
|
||||
flags_rebuild();
|
||||
if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 22;
|
||||
break;
|
||||
case 0x30: /*DIV AX,w*/
|
||||
templ = (DX << 16) | AX;
|
||||
if (dst) templ2 = templ / dst;
|
||||
if (dst && !(templ2 & 0xffff0000))
|
||||
{
|
||||
DX = templ % dst;
|
||||
AX = (templ / dst) & 0xffff;
|
||||
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= is486 ? 24 : 22;
|
||||
break;
|
||||
case 0x38: /*IDIV AX,w*/
|
||||
tempws = (int)((DX << 16)|AX);
|
||||
if (dst) tempws2 = tempws / (int)((int16_t)dst);
|
||||
temps16 = tempws2 & 0xffff;
|
||||
if ((dst != 0) && ((int)temps16 == tempws2))
|
||||
{
|
||||
DX = tempws % (int)((int16_t)dst);
|
||||
AX = tempws2 & 0xffff;
|
||||
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= 27;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opF7_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ, templ2;
|
||||
int tempws, tempws2;
|
||||
int16_t temps16;
|
||||
uint16_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteaw(); if (abrt) return 0;
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST w*/
|
||||
src = getword(); if (abrt) return 0;
|
||||
setznp16(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT w*/
|
||||
seteaw(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x18: /*NEG w*/
|
||||
setsub16(0, dst);
|
||||
seteaw(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mm;
|
||||
break;
|
||||
case 0x20: /*MUL AX,w*/
|
||||
templ = AX * dst;
|
||||
AX = templ & 0xFFFF;
|
||||
DX = templ >> 16;
|
||||
flags_rebuild();
|
||||
if (DX) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 21;
|
||||
break;
|
||||
case 0x28: /*IMUL AX,w*/
|
||||
templ = (int)((int16_t)AX) * (int)((int16_t)dst);
|
||||
AX = templ & 0xFFFF;
|
||||
DX = templ >> 16;
|
||||
flags_rebuild();
|
||||
if (DX && DX != 0xFFFF) flags |= (C_FLAG | V_FLAG);
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
cycles -= 22;
|
||||
break;
|
||||
case 0x30: /*DIV AX,w*/
|
||||
templ = (DX << 16) | AX;
|
||||
if (dst) templ2 = templ / dst;
|
||||
if (dst && !(templ2 & 0xffff0000))
|
||||
{
|
||||
DX = templ % dst;
|
||||
AX = (templ / dst) & 0xffff;
|
||||
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= is486 ? 24 : 22;
|
||||
break;
|
||||
case 0x38: /*IDIV AX,w*/
|
||||
tempws = (int)((DX << 16)|AX);
|
||||
if (dst) tempws2 = tempws / (int)((int16_t)dst);
|
||||
temps16 = tempws2 & 0xffff;
|
||||
if ((dst != 0) && ((int)temps16 == tempws2))
|
||||
{
|
||||
DX = tempws % (int)((int16_t)dst);
|
||||
AX = tempws2 & 0xffff;
|
||||
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2);
|
||||
x86_int(0);
|
||||
}
|
||||
cycles -= 27;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opF7_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint64_t temp64;
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
dst = geteal(); if (abrt) return 0;
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST l*/
|
||||
src = getlong(); if (abrt) return 0;
|
||||
setznp32(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT l*/
|
||||
seteal(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mml;
|
||||
break;
|
||||
case 0x18: /*NEG l*/
|
||||
setsub32(0, dst);
|
||||
seteal(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mml;
|
||||
break;
|
||||
case 0x20: /*MUL EAX,l*/
|
||||
temp64 = (uint64_t)EAX * (uint64_t)dst;
|
||||
EAX = temp64 & 0xffffffff;
|
||||
EDX = temp64 >> 32;
|
||||
flags_rebuild();
|
||||
if (EDX) flags |= (C_FLAG|V_FLAG);
|
||||
else flags &= ~(C_FLAG|V_FLAG);
|
||||
cycles -= 21;
|
||||
break;
|
||||
case 0x28: /*IMUL EAX,l*/
|
||||
temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst;
|
||||
EAX = temp64 & 0xffffffff;
|
||||
EDX = temp64 >> 32;
|
||||
flags_rebuild();
|
||||
if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG);
|
||||
else flags &= ~(C_FLAG|V_FLAG);
|
||||
cycles -= 38;
|
||||
break;
|
||||
case 0x30: /*DIV EAX,l*/
|
||||
divl(dst);
|
||||
if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
|
||||
cycles -= (is486) ? 40 : 38;
|
||||
break;
|
||||
case 0x38: /*IDIV EAX,l*/
|
||||
idivl((int32_t)dst);
|
||||
if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
|
||||
cycles -= 43;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opF7_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint64_t temp64;
|
||||
uint32_t src, dst;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
dst = geteal(); if (abrt) return 0;
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*TEST l*/
|
||||
src = getlong(); if (abrt) return 0;
|
||||
setznp32(src & dst);
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 2);
|
||||
else cycles -= ((mod == 3) ? 2 : 5);
|
||||
break;
|
||||
case 0x10: /*NOT l*/
|
||||
seteal(~dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mml;
|
||||
break;
|
||||
case 0x18: /*NEG l*/
|
||||
setsub32(0, dst);
|
||||
seteal(0 - dst);
|
||||
cycles -= (mod == 3) ? timing_rr : timing_mml;
|
||||
break;
|
||||
case 0x20: /*MUL EAX,l*/
|
||||
temp64 = (uint64_t)EAX * (uint64_t)dst;
|
||||
EAX = temp64 & 0xffffffff;
|
||||
EDX = temp64 >> 32;
|
||||
flags_rebuild();
|
||||
if (EDX) flags |= (C_FLAG|V_FLAG);
|
||||
else flags &= ~(C_FLAG|V_FLAG);
|
||||
cycles -= 21;
|
||||
break;
|
||||
case 0x28: /*IMUL EAX,l*/
|
||||
temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst;
|
||||
EAX = temp64 & 0xffffffff;
|
||||
EDX = temp64 >> 32;
|
||||
flags_rebuild();
|
||||
if (EDX && EDX != 0xffffffff) flags |= (C_FLAG|V_FLAG);
|
||||
else flags &= ~(C_FLAG|V_FLAG);
|
||||
cycles -= 38;
|
||||
break;
|
||||
case 0x30: /*DIV EAX,l*/
|
||||
divl(dst);
|
||||
if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
|
||||
cycles -= (is486) ? 40 : 38;
|
||||
break;
|
||||
case 0x38: /*IDIV EAX,l*/
|
||||
idivl((int32_t)dst);
|
||||
if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/
|
||||
cycles -= 43;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad F7 opcode %02X\n", rmdat & 0x38);
|
||||
x86illegal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opHLT(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
if (!((flags&I_FLAG) && pic_intpending && !ssegs))
|
||||
{
|
||||
cycles -= 100;
|
||||
pc--;
|
||||
}
|
||||
else
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opLOCK(uint32_t fetchdat)
|
||||
{
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int opBOUND_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int16_t low, high;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
low = geteaw();
|
||||
high = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
|
||||
if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high))
|
||||
{
|
||||
x86_int(5);
|
||||
}
|
||||
|
||||
cycles -= is486 ? 7 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBOUND_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int16_t low, high;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
low = geteaw();
|
||||
high = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
|
||||
if (((int16_t)regs[reg].w < low) || ((int16_t)regs[reg].w > high))
|
||||
{
|
||||
x86_int(5);
|
||||
}
|
||||
|
||||
cycles -= is486 ? 7 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opBOUND_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int32_t low, high;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
low = geteal();
|
||||
high = readmeml(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
|
||||
if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high))
|
||||
{
|
||||
x86_int(5);
|
||||
}
|
||||
|
||||
cycles -= is486 ? 7 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opBOUND_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int32_t low, high;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
low = geteal();
|
||||
high = readmeml(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
|
||||
if (((int32_t)regs[reg].l < low) || ((int32_t)regs[reg].l > high))
|
||||
{
|
||||
x86_int(5);
|
||||
}
|
||||
|
||||
cycles -= is486 ? 7 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opCLTS(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't CLTS\n");
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
cr0 &= ~8;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINVD(uint32_t fetchdat)
|
||||
{
|
||||
if (!is486)
|
||||
{
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
cycles -= 1000;
|
||||
return 0;
|
||||
}
|
||||
static int opWBINVD(uint32_t fetchdat)
|
||||
{
|
||||
if (!is486)
|
||||
{
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
cycles -= 10000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int opLOADALL(uint32_t fetchdat)
|
||||
{
|
||||
flags = (readmemw(0, 0x818) & 0xffd5) | 2;
|
||||
flags_extract();
|
||||
pc = readmemw(0, 0x81A);
|
||||
DS = readmemw(0, 0x81E);
|
||||
SS = readmemw(0, 0x820);
|
||||
CS = readmemw(0, 0x822);
|
||||
ES = readmemw(0, 0x824);
|
||||
DI = readmemw(0, 0x826);
|
||||
SI = readmemw(0, 0x828);
|
||||
BP = readmemw(0, 0x82A);
|
||||
SP = readmemw(0, 0x82C);
|
||||
BX = readmemw(0, 0x82E);
|
||||
DX = readmemw(0, 0x830);
|
||||
CX = readmemw(0, 0x832);
|
||||
AX = readmemw(0, 0x834);
|
||||
es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16);
|
||||
cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16);
|
||||
ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16);
|
||||
ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16);
|
||||
cycles-=195;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCPUID(uint32_t fetchdat)
|
||||
{
|
||||
if (CPUID)
|
||||
{
|
||||
cpu_CPUID();
|
||||
cycles -= 9;
|
||||
return 0;
|
||||
}
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
559
src/x86_ops_mov.h
Normal file
559
src/x86_ops_mov.h
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
static int opMOV_AL_imm(uint32_t fetchdat)
|
||||
{
|
||||
AL = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_AH_imm(uint32_t fetchdat)
|
||||
{
|
||||
AH = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_BL_imm(uint32_t fetchdat)
|
||||
{
|
||||
BL = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_BH_imm(uint32_t fetchdat)
|
||||
{
|
||||
BH = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_CL_imm(uint32_t fetchdat)
|
||||
{
|
||||
CL = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_CH_imm(uint32_t fetchdat)
|
||||
{
|
||||
CH = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_DL_imm(uint32_t fetchdat)
|
||||
{
|
||||
DL = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_DH_imm(uint32_t fetchdat)
|
||||
{
|
||||
DH = getbytef();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_AX_imm(uint32_t fetchdat)
|
||||
{
|
||||
AX = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_BX_imm(uint32_t fetchdat)
|
||||
{
|
||||
BX = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_CX_imm(uint32_t fetchdat)
|
||||
{
|
||||
CX = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_DX_imm(uint32_t fetchdat)
|
||||
{
|
||||
DX = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_SI_imm(uint32_t fetchdat)
|
||||
{
|
||||
SI = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_DI_imm(uint32_t fetchdat)
|
||||
{
|
||||
DI = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_BP_imm(uint32_t fetchdat)
|
||||
{
|
||||
BP = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_SP_imm(uint32_t fetchdat)
|
||||
{
|
||||
SP = getwordf();
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_EAX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
EAX = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EBX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
EBX = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_ECX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
ECX = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EDX_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
EDX = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_ESI_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
ESI = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EDI_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
EDI = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EBP_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
EBP = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_ESP_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getlong(); if (abrt) return 0;
|
||||
ESP = templ;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_b_imm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = readmemb(cs,pc); pc++; if (abrt) return 0;
|
||||
seteab(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_b_imm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = getbyte(); if (abrt) return 0;
|
||||
seteab(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_w_imm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = getword(); if (abrt) return 0;
|
||||
seteaw(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_w_imm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = getword(); if (abrt) return 0;
|
||||
seteaw(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_l_imm_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = getlong(); if (abrt) return 0;
|
||||
seteal(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_l_imm_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = getlong(); if (abrt) return 0;
|
||||
seteal(temp);
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opMOV_AL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
uint8_t temp = readmemb(ds, addr); if (abrt) return 0;
|
||||
AL = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_AL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
uint8_t temp = readmemb(ds, addr); if (abrt) return 0;
|
||||
AL = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_AX_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
uint16_t temp = readmemw(ds, addr); if (abrt) return 0;
|
||||
AX = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_AX_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
uint16_t temp = readmemw(ds, addr); if (abrt) return 0;
|
||||
AX = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EAX_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf(); if (abrt) return 0;
|
||||
uint32_t temp = readmeml(ds, addr); if (abrt) return 0;
|
||||
EAX = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_EAX_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong(); if (abrt) return 0;
|
||||
uint32_t temp = readmeml(ds, addr); if (abrt) return 0;
|
||||
EAX = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_a16_AL(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
writememb(ds, addr, AL);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_a32_AL(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
writememb(ds, addr, AL);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_a16_AX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
writememw(ds, addr, AX);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_a32_AX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
writememw(ds, addr, AX);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_a16_EAX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr = getwordf();
|
||||
writememl(ds, addr, EAX);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_a32_EAX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = getlong();
|
||||
writememl(ds, addr, EAX);
|
||||
cycles -= (is486) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opLEA_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
regs[reg].w = eaaddr;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opLEA_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
regs[reg].w = eaaddr;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLEA_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
regs[reg].l = eaaddr & 0xffff;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
static int opLEA_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
regs[reg].l = eaaddr;
|
||||
cycles -= timing_rr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int opXLAT_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = (BX + AL)&0xFFFF;
|
||||
uint8_t temp = readmemb(ds, addr); if (abrt) return 0;
|
||||
AL = temp;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
int opXLAT_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr = EBX + AL;
|
||||
uint8_t temp = readmemb(ds, addr); if (abrt) return 0;
|
||||
AL = temp;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_b_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
setr8(fetchdat & 7, getr8((fetchdat >> 3) & 7));
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
seteab(getr8(reg));
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_b_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
setr8(fetchdat & 7, getr8((fetchdat >> 3) & 7));
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
seteab(getr8(reg));
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_w_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[fetchdat & 7].w = regs[(fetchdat >> 3) & 7].w;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
seteaw(regs[reg].w);
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_w_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[fetchdat & 7].w = regs[(fetchdat >> 3) & 7].w;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
seteaw(regs[reg].w);
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_l_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[fetchdat & 7].l = regs[(fetchdat >> 3) & 7].l;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
seteal(regs[reg].l);
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_l_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[fetchdat & 7].l = regs[(fetchdat >> 3) & 7].l;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
seteal(regs[reg].l);
|
||||
cycles -= is486 ? 1 : 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_r_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
setr8((fetchdat >> 3) & 7, getr8(fetchdat & 7));
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
setr8(reg, temp);
|
||||
cycles -= is486 ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
setr8((fetchdat >> 3) & 7, getr8(fetchdat & 7));
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
setr8(reg, temp);
|
||||
cycles -= is486 ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[(fetchdat >> 3) & 7].w = regs[fetchdat & 7].w;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].w = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[(fetchdat >> 3) & 7].w = regs[fetchdat & 7].w;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].w = temp;
|
||||
cycles -= (is486) ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[(fetchdat >> 3) & 7].l = regs[fetchdat & 7].l;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
regs[reg].l = temp;
|
||||
cycles -= is486 ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((uint8_t)fetchdat >= 0xc0)
|
||||
{
|
||||
pc++;
|
||||
regs[(fetchdat >> 3) & 7].l = regs[fetchdat & 7].l;
|
||||
cycles -= timing_rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
regs[reg].l = temp;
|
||||
cycles -= is486 ? 1 : 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
232
src/x86_ops_mov_ctrl.h
Normal file
232
src/x86_ops_mov_ctrl.h
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
static int opMOV_r_CRx_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from CRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
regs[rm].l = cr0;
|
||||
if (is486) regs[rm].l |= 0x10; /*ET hardwired on 486*/
|
||||
break;
|
||||
case 2:
|
||||
regs[rm].l = cr2;
|
||||
break;
|
||||
case 3:
|
||||
regs[rm].l = cr3;
|
||||
break;
|
||||
default:
|
||||
pclog("Bad read of CR%i %i\n",rmdat&7,reg);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_CRx_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from CRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
regs[rm].l = cr0;
|
||||
if (is486) regs[rm].l |= 0x10; /*ET hardwired on 486*/
|
||||
break;
|
||||
case 2:
|
||||
regs[rm].l = cr2;
|
||||
break;
|
||||
case 3:
|
||||
regs[rm].l = cr3;
|
||||
break;
|
||||
default:
|
||||
pclog("Bad read of CR%i %i\n",rmdat&7,reg);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_r_DRx_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from DRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
regs[rm].l = 0;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_DRx_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from DRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
regs[rm].l = 0;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_CRx_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load CRx\n");
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
if ((regs[rm].l ^ cr0) & 0x80000001) flushmmucache();
|
||||
cr0 = regs[rm].l;
|
||||
if (cpu_16bitbus) cr0 |= 0x10;
|
||||
if (!(cr0 & 0x80000000)) mmu_perm=4;
|
||||
break;
|
||||
case 2:
|
||||
cr2 = regs[rm].l;
|
||||
break;
|
||||
case 3:
|
||||
cr3 = regs[rm].l & ~0xfff;
|
||||
flushmmucache();
|
||||
break;
|
||||
default:
|
||||
pclog("Bad load CR%i\n", reg);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
cycles -= 10;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_CRx_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load CRx\n");
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
if ((regs[rm].l ^ cr0) & 0x80000001) flushmmucache();
|
||||
cr0 = regs[rm].l;
|
||||
if (cpu_16bitbus) cr0 |= 0x10;
|
||||
if (!(cr0 & 0x80000000)) mmu_perm=4;
|
||||
break;
|
||||
case 2:
|
||||
cr2 = regs[rm].l;
|
||||
break;
|
||||
case 3:
|
||||
cr3 = regs[rm].l & ~0xfff;
|
||||
flushmmucache();
|
||||
break;
|
||||
default:
|
||||
pclog("Bad load CR%i\n", reg);
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
cycles -= 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_DRx_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load DRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_DRx_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load DRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_r_TRx_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from TRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
regs[rm].l = 0;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_r_TRx_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load from TRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_32(fetchdat);
|
||||
regs[rm].l = 0;
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_TRx_r_a16(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load TRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_TRx_r_a32(uint32_t fetchdat)
|
||||
{
|
||||
if ((CPL || (eflags&VM_FLAG)) && (cr0&1))
|
||||
{
|
||||
pclog("Can't load TRx\n");
|
||||
x86gpf(NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
fetch_ea_16(fetchdat);
|
||||
cycles -= 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
396
src/x86_ops_mov_seg.h
Normal file
396
src/x86_ops_mov_seg.h
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
static int opMOV_w_seg_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
seteaw(ES);
|
||||
break;
|
||||
case 0x08: /*CS*/
|
||||
seteaw(CS);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
if (ssegs) ds = oldds;
|
||||
seteaw(DS);
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
if (ssegs) ss = oldss;
|
||||
seteaw(SS);
|
||||
break;
|
||||
case 0x20: /*FS*/
|
||||
seteaw(FS);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
seteaw(GS);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 3);
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_w_seg_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
seteaw(ES);
|
||||
break;
|
||||
case 0x08: /*CS*/
|
||||
seteaw(CS);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
if (ssegs) ds = oldds;
|
||||
seteaw(DS);
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
if (ssegs) ss = oldss;
|
||||
seteaw(SS);
|
||||
break;
|
||||
case 0x20: /*FS*/
|
||||
seteaw(FS);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
seteaw(GS);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_l_seg_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
if (mod == 3) regs[rm].l = ES;
|
||||
else seteaw(ES);
|
||||
break;
|
||||
case 0x08: /*CS*/
|
||||
if (mod == 3) regs[rm].l = CS;
|
||||
else seteaw(CS);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
if (ssegs) ds = oldds;
|
||||
if (mod == 3) regs[rm].l = DS;
|
||||
else seteaw(DS);
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
if (ssegs) ss = oldss;
|
||||
if (mod == 3) regs[rm].l = SS;
|
||||
else seteaw(SS);
|
||||
break;
|
||||
case 0x20: /*FS*/
|
||||
if (mod == 3) regs[rm].l = FS;
|
||||
else seteaw(FS);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
if (mod == 3) regs[rm].l = GS;
|
||||
else seteaw(GS);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 3);
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_l_seg_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
if (mod == 3) regs[rm].l = ES;
|
||||
else seteaw(ES);
|
||||
break;
|
||||
case 0x08: /*CS*/
|
||||
if (mod == 3) regs[rm].l = CS;
|
||||
else seteaw(CS);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
if (ssegs) ds = oldds;
|
||||
if (mod == 3) regs[rm].l = DS;
|
||||
else seteaw(DS);
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
if (ssegs) ss = oldss;
|
||||
if (mod == 3) regs[rm].l = SS;
|
||||
else seteaw(SS);
|
||||
break;
|
||||
case 0x20: /*FS*/
|
||||
if (mod == 3) regs[rm].l = FS;
|
||||
else seteaw(FS);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
if (mod == 3) regs[rm].l = GS;
|
||||
else seteaw(GS);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOV_seg_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t new_seg;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
new_seg=geteaw(); if (abrt) return 0;
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
loadseg(new_seg, &_es);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
loadseg(new_seg, &_ds);
|
||||
if (ssegs) oldds = ds;
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
loadseg(new_seg, &_ss);
|
||||
if (ssegs)
|
||||
{
|
||||
ds = oldds;
|
||||
rds = DS;
|
||||
ssegs = 0;
|
||||
}
|
||||
op32 = use32;
|
||||
return 1;
|
||||
case 0x20: /*FS*/
|
||||
loadseg(new_seg, &_fs);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
loadseg(new_seg, &_gs);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opMOV_seg_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t new_seg;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
new_seg=geteaw(); if (abrt) return 0;
|
||||
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
loadseg(new_seg, &_es);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
loadseg(new_seg, &_ds);
|
||||
if (ssegs) oldds = ds;
|
||||
break;
|
||||
case 0x10: /*SS*/
|
||||
loadseg(new_seg, &_ss);
|
||||
if (ssegs)
|
||||
{
|
||||
ds = oldds;
|
||||
rds = DS;
|
||||
ssegs = 0;
|
||||
}
|
||||
op32 = use32;
|
||||
return 1;
|
||||
case 0x20: /*FS*/
|
||||
loadseg(new_seg, &_fs);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
loadseg(new_seg, &_gs);
|
||||
break;
|
||||
}
|
||||
|
||||
cycles -= ((mod == 3) ? 2 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opLDS_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr, seg;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
addr = readmemw(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
loadseg(seg, &_ds); if (abrt) return 0;
|
||||
regs[reg].w = addr;
|
||||
if (ssegs) oldds = ds;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLDS_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr, seg;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
addr = readmemw(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
loadseg(seg, &_ds); if (abrt) return 0;
|
||||
regs[reg].w = addr;
|
||||
if (ssegs) oldds = ds;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLDS_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint16_t seg;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
addr = readmeml(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
loadseg(seg, &_ds); if (abrt) return 0;
|
||||
regs[reg].l = addr;
|
||||
if (ssegs) oldds = ds;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLDS_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint16_t seg;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
addr = readmeml(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
loadseg(seg, &_ds); if (abrt) return 0;
|
||||
regs[reg].l = addr;
|
||||
if (ssegs) oldds = ds;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLSS_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr, seg;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
addr = readmemw(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
loadseg(seg, &_ss); if (abrt) return 0;
|
||||
regs[reg].w = addr;
|
||||
oldss = ss;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLSS_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t addr, seg;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
addr = readmemw(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
|
||||
loadseg(seg, &_ss); if (abrt) return 0;
|
||||
regs[reg].w = addr;
|
||||
oldss = ss;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLSS_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint16_t seg;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
addr = readmeml(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
loadseg(seg, &_ss); if (abrt) return 0;
|
||||
regs[reg].l = addr;
|
||||
oldss = ss;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opLSS_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint16_t seg;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
addr = readmeml(easeg, eaaddr);
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
|
||||
loadseg(seg, &_ss); if (abrt) return 0;
|
||||
regs[reg].l = addr;
|
||||
oldss = ss;
|
||||
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define opLsel(name, sel) \
|
||||
static int opL ## name ## _w_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint16_t addr, seg; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
addr = readmemw(easeg, eaaddr); \
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; \
|
||||
loadseg(seg, &sel); if (abrt) return 0; \
|
||||
regs[reg].w = addr; \
|
||||
\
|
||||
cycles -= 7; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opL ## name ## _w_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint16_t addr, seg; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
addr = readmemw(easeg, eaaddr); \
|
||||
seg = readmemw(easeg, eaaddr + 2); if (abrt) return 0; \
|
||||
loadseg(seg, &sel); if (abrt) return 0; \
|
||||
regs[reg].w = addr; \
|
||||
\
|
||||
cycles -= 7; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opL ## name ## _l_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint32_t addr; \
|
||||
uint16_t seg; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
addr = readmeml(easeg, eaaddr); \
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; \
|
||||
loadseg(seg, &sel); if (abrt) return 0; \
|
||||
regs[reg].l = addr; \
|
||||
\
|
||||
cycles -= 7; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opL ## name ## _l_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint32_t addr; \
|
||||
uint16_t seg; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
addr = readmeml(easeg, eaaddr); \
|
||||
seg = readmemw(easeg, eaaddr + 4); if (abrt) return 0; \
|
||||
loadseg(seg, &sel); if (abrt) return 0; \
|
||||
regs[reg].l = addr; \
|
||||
\
|
||||
cycles -= 7; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opLsel(ES, _es)
|
||||
opLsel(FS, _fs)
|
||||
opLsel(GS, _gs)
|
||||
145
src/x86_ops_movx.h
Normal file
145
src/x86_ops_movx.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
static int opMOVZX_w_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].w = (uint16_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVZX_w_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].w = (uint16_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVZX_l_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVZX_l_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVZX_l_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVZX_l_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOVSX_w_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].w = (uint16_t)temp;
|
||||
if (temp & 0x80)
|
||||
regs[reg].w |= 0xff00;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSX_w_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].w = (uint16_t)temp;
|
||||
if (temp & 0x80)
|
||||
regs[reg].w |= 0xff00;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSX_l_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
if (temp & 0x80)
|
||||
regs[reg].l |= 0xffffff00;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSX_l_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
if (temp & 0x80)
|
||||
regs[reg].l |= 0xffffff00;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSX_l_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
if (temp & 0x8000)
|
||||
regs[reg].l |= 0xffff0000;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSX_l_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
regs[reg].l = (uint32_t)temp;
|
||||
if (temp & 0x8000)
|
||||
regs[reg].l |= 0xffff0000;
|
||||
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
13
src/x86_ops_msr.h
Normal file
13
src/x86_ops_msr.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
static int opRDTSC(uint32_t fetchdat)
|
||||
{
|
||||
if (!cpu_hasrdtsc)
|
||||
{
|
||||
pc = oldpc;
|
||||
x86illegal();
|
||||
return 0;
|
||||
}
|
||||
EAX = tsc & 0xffffffff;
|
||||
EDX = tsc >> 32;
|
||||
cycles--;
|
||||
return 0;
|
||||
}
|
||||
222
src/x86_ops_mul.h
Normal file
222
src/x86_ops_mul.h
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
static int opIMUL_w_iw_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ;
|
||||
int16_t tempw, tempw2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
tempw = geteaw(); if (abrt) return 0;
|
||||
tempw2 = getword(); if (abrt) return 0;
|
||||
|
||||
templ = ((int)tempw) * ((int)tempw2);
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) != 0 && (templ >> 16) != 0xffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].w = templ & 0xffff;
|
||||
|
||||
cycles -= (mod == 3) ? 14 : 17;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_w_iw_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ;
|
||||
int16_t tempw, tempw2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
tempw = geteaw(); if (abrt) return 0;
|
||||
tempw2 = getword(); if (abrt) return 0;
|
||||
|
||||
templ = ((int)tempw) * ((int)tempw2);
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) != 0 && (templ >> 16) != 0xffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].w = templ & 0xffff;
|
||||
|
||||
cycles -= (mod == 3) ? 14 : 17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIMUL_l_il_a16(uint32_t fetchdat)
|
||||
{
|
||||
int64_t temp64;
|
||||
int32_t templ, templ2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
templ = geteal(); if (abrt) return 0;
|
||||
templ2 = getlong(); if (abrt) return 0;
|
||||
|
||||
temp64 = ((int64_t)templ) * ((int64_t)templ2);
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].l = temp64 & 0xffffffff;
|
||||
|
||||
cycles-=25;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_l_il_a32(uint32_t fetchdat)
|
||||
{
|
||||
int64_t temp64;
|
||||
int32_t templ, templ2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
templ = geteal(); if (abrt) return 0;
|
||||
templ2 = getlong(); if (abrt) return 0;
|
||||
|
||||
temp64 = ((int64_t)templ) * ((int64_t)templ2);
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].l = temp64 & 0xffffffff;
|
||||
|
||||
cycles-=25;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIMUL_w_ib_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ;
|
||||
int16_t tempw, tempw2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
tempw = geteaw(); if (abrt) return 0;
|
||||
tempw2 = getbyte(); if (abrt) return 0;
|
||||
if (tempw2 & 0x80) tempw2 |= 0xff00;
|
||||
|
||||
templ = ((int)tempw) * ((int)tempw2);
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) != 0 && ((templ >> 16) & 0xffff) != 0xffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].w = templ & 0xffff;
|
||||
|
||||
cycles -= (mod == 3) ? 14 : 17;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_w_ib_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ;
|
||||
int16_t tempw, tempw2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
tempw = geteaw(); if (abrt) return 0;
|
||||
tempw2 = getbyte(); if (abrt) return 0;
|
||||
if (tempw2 & 0x80) tempw2 |= 0xff00;
|
||||
|
||||
templ = ((int)tempw) * ((int)tempw2);
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) != 0 && ((templ >> 16) & 0xffff) != 0xffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].w = templ & 0xffff;
|
||||
|
||||
cycles -= (mod == 3) ? 14 : 17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIMUL_l_ib_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint64_t temp64;
|
||||
int32_t templ, templ2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
templ = geteal(); if (abrt) return 0;
|
||||
templ2 = getbyte(); if (abrt) return 0;
|
||||
if (templ2 & 0x80) templ2 |= 0xffffff00;
|
||||
|
||||
temp64 = ((int64_t)templ)*((int64_t)templ2);
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].l = temp64 & 0xffffffff;
|
||||
|
||||
cycles -= 20;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_l_ib_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint64_t temp64;
|
||||
int32_t templ, templ2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
templ = geteal(); if (abrt) return 0;
|
||||
templ2 = getbyte(); if (abrt) return 0;
|
||||
if (templ2 & 0x80) templ2 |= 0xffffff00;
|
||||
|
||||
temp64 = ((int64_t)templ)*((int64_t)templ2);
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) != 0 && (temp64 >> 32) != 0xffffffff) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
regs[reg].l = temp64 & 0xffffffff;
|
||||
|
||||
cycles -= 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int opIMUL_w_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int32_t templ;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
templ = (int32_t)(int16_t)regs[reg].w * (int32_t)(int16_t)geteaw();
|
||||
if (abrt) return 0;
|
||||
regs[reg].w = templ & 0xFFFF;
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) && (templ >> 16) != 0xFFFF) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
|
||||
cycles -= 18;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_w_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int32_t templ;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
templ = (int32_t)(int16_t)regs[reg].w * (int32_t)(int16_t)geteaw();
|
||||
if (abrt) return 0;
|
||||
regs[reg].w = templ & 0xFFFF;
|
||||
flags_rebuild();
|
||||
if ((templ >> 16) && (templ >> 16) != 0xFFFF) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
|
||||
cycles -= 18;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIMUL_l_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int64_t temp64;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp64 = (int64_t)(int32_t)regs[reg].l * (int64_t)(int32_t)geteal();
|
||||
if (abrt) return 0;
|
||||
regs[reg].l = temp64 & 0xFFFFFFFF;
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) && (temp64 >> 32) != 0xFFFFFFFF) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
|
||||
cycles -= 30;
|
||||
return 0;
|
||||
}
|
||||
static int opIMUL_l_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int64_t temp64;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp64 = (int64_t)(int32_t)regs[reg].l * (int64_t)(int32_t)geteal();
|
||||
if (abrt) return 0;
|
||||
regs[reg].l = temp64 & 0xFFFFFFFF;
|
||||
flags_rebuild();
|
||||
if ((temp64 >> 32) && (temp64 >> 32) != 0xFFFFFFFF) flags |= C_FLAG | V_FLAG;
|
||||
else flags &= ~(C_FLAG | V_FLAG);
|
||||
|
||||
cycles -= 30;
|
||||
return 0;
|
||||
}
|
||||
|
||||
404
src/x86_ops_pmode.h
Normal file
404
src/x86_ops_pmode.h
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
static int opARPL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp_seg;
|
||||
|
||||
NOTRM
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
temp_seg = geteaw(); if (abrt) return 0;
|
||||
|
||||
flags_rebuild();
|
||||
if ((temp_seg & 3) < (regs[reg].w & 3))
|
||||
{
|
||||
temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3);
|
||||
seteaw(temp_seg); if (abrt) return 0;
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
else
|
||||
flags &= ~Z_FLAG;
|
||||
|
||||
cycles -= is486 ? 9 : 20;
|
||||
return 0;
|
||||
}
|
||||
static int opARPL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp_seg;
|
||||
|
||||
NOTRM
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
temp_seg = geteaw(); if (abrt) return 0;
|
||||
|
||||
flags_rebuild();
|
||||
if ((temp_seg & 3) < (regs[reg].w & 3))
|
||||
{
|
||||
temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3);
|
||||
seteaw(temp_seg); if (abrt) return 0;
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
else
|
||||
flags &= ~Z_FLAG;
|
||||
|
||||
cycles -= is486 ? 9 : 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define opLAR(name, fetch_ea, is32) \
|
||||
static int opLAR_ ## name(uint32_t fetchdat) \
|
||||
{ \
|
||||
int valid; \
|
||||
uint16_t sel, desc; \
|
||||
\
|
||||
NOTRM \
|
||||
fetch_ea(fetchdat); \
|
||||
\
|
||||
sel = geteaw(); if (abrt) return 0; \
|
||||
\
|
||||
flags_rebuild(); \
|
||||
if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \
|
||||
valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \
|
||||
if (valid) \
|
||||
{ \
|
||||
cpl_override = 1; \
|
||||
desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \
|
||||
cpl_override = 0; if (abrt) return 0; \
|
||||
} \
|
||||
flags &= ~Z_FLAG; \
|
||||
if ((desc & 0x1f00) == 0x000) valid = 0; \
|
||||
if ((desc & 0x1f00) == 0x800) valid = 0; \
|
||||
if ((desc & 0x1f00) == 0xa00) valid = 0; \
|
||||
if ((desc & 0x1f00) == 0xd00) valid = 0; \
|
||||
if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \
|
||||
{ \
|
||||
int dpl = (desc >> 13) & 3; \
|
||||
if (dpl < CPL || dpl < (sel & 3)) valid = 0; \
|
||||
} \
|
||||
if (valid) \
|
||||
{ \
|
||||
flags |= Z_FLAG; \
|
||||
cpl_override = 1; \
|
||||
if (is32) \
|
||||
regs[reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \
|
||||
else \
|
||||
regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \
|
||||
cpl_override = 0; \
|
||||
} \
|
||||
cycles -= 11; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opLAR(w_a16, fetch_ea_16, 0)
|
||||
opLAR(w_a32, fetch_ea_32, 0)
|
||||
opLAR(l_a16, fetch_ea_16, 1)
|
||||
opLAR(l_a32, fetch_ea_32, 1)
|
||||
|
||||
#define opLSL(name, fetch_ea, is32) \
|
||||
static int opLSL_ ## name(uint32_t fetchdat) \
|
||||
{ \
|
||||
int valid; \
|
||||
uint16_t sel, desc; \
|
||||
\
|
||||
NOTRM \
|
||||
fetch_ea(fetchdat); \
|
||||
\
|
||||
sel = geteaw(); if (abrt) return 0; \
|
||||
flags_rebuild(); \
|
||||
flags &= ~Z_FLAG; \
|
||||
if (!(sel & 0xfffc)) return 0; /*Null selector*/ \
|
||||
valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \
|
||||
if (valid) \
|
||||
{ \
|
||||
cpl_override = 1; \
|
||||
desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \
|
||||
cpl_override = 0; if (abrt) return 0; \
|
||||
} \
|
||||
if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \
|
||||
if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \
|
||||
if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \
|
||||
if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \
|
||||
{ \
|
||||
int rpl = (desc >> 13) & 3; \
|
||||
if (rpl < CPL || rpl < (sel & 3)) valid = 0; \
|
||||
} \
|
||||
if (valid) \
|
||||
{ \
|
||||
flags |= Z_FLAG; \
|
||||
cpl_override = 1; \
|
||||
if (is32) \
|
||||
{ \
|
||||
regs[reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \
|
||||
regs[reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \
|
||||
if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \
|
||||
{ \
|
||||
regs[reg].l <<= 12; \
|
||||
regs[reg].l |= 0xFFF; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \
|
||||
cpl_override = 0; \
|
||||
} \
|
||||
cycles -= 10; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opLSL(w_a16, fetch_ea_16, 0)
|
||||
opLSL(w_a32, fetch_ea_32, 0)
|
||||
opLSL(l_a16, fetch_ea_16, 1)
|
||||
opLSL(l_a32, fetch_ea_32, 1)
|
||||
|
||||
|
||||
static inline int op0F00_common(uint32_t fetchdat)
|
||||
{
|
||||
int dpl, valid, granularity;
|
||||
uint32_t addr, base, limit;
|
||||
uint16_t desc, sel;
|
||||
uint8_t access;
|
||||
|
||||
// pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc);
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*SLDT*/
|
||||
seteaw(ldt.seg);
|
||||
cycles -= 4;
|
||||
break;
|
||||
case 0x08: /*STR*/
|
||||
seteaw(tr.seg);
|
||||
cycles -= 4;
|
||||
break;
|
||||
case 0x10: /*LLDT*/
|
||||
if ((CPL || eflags&VM_FLAG) && (cr0&1))
|
||||
{
|
||||
pclog("Invalid LLDT!\n");
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
sel = geteaw(); if (abrt) return 0;
|
||||
addr = (sel & ~7) + gdt.base;
|
||||
limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
|
||||
base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24);
|
||||
access = readmemb(0, addr + 5);
|
||||
granularity = readmemb(0, addr + 6) & 0x80;
|
||||
if (abrt) return 0;
|
||||
ldt.limit = limit;
|
||||
ldt.access = access;
|
||||
if (granularity)
|
||||
{
|
||||
ldt.limit <<= 12;
|
||||
ldt.limit |= 0xfff;
|
||||
}
|
||||
ldt.base = base;
|
||||
ldt.seg = sel;
|
||||
cycles -= 20;
|
||||
break;
|
||||
case 0x18: /*LTR*/
|
||||
if ((CPL || eflags&VM_FLAG) && (cr0&1))
|
||||
{
|
||||
pclog("Invalid LTR!\n");
|
||||
x86gpf(NULL,0);
|
||||
break;
|
||||
}
|
||||
sel = geteaw(); if (abrt) return 0;
|
||||
addr = (sel & ~7) + gdt.base;
|
||||
limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
|
||||
base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24);
|
||||
access = readmemb(0, addr + 5);
|
||||
granularity = readmemb(0, addr + 6) & 0x80;
|
||||
if (abrt) return 0;
|
||||
tr.seg = sel;
|
||||
tr.limit = limit;
|
||||
tr.access = access;
|
||||
if (granularity)
|
||||
{
|
||||
tr.limit <<= 12;
|
||||
tr.limit |= 0xFFF;
|
||||
}
|
||||
tr.base = base;
|
||||
cycles -= 20;
|
||||
break;
|
||||
case 0x20: /*VERR*/
|
||||
sel = geteaw(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
flags &= ~Z_FLAG;
|
||||
if (!(sel & 0xfffc)) return 0; /*Null selector*/
|
||||
cpl_override = 1;
|
||||
valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
|
||||
desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4);
|
||||
cpl_override = 0; if (abrt) return 0;
|
||||
if (!(desc & 0x1000)) valid = 0;
|
||||
if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/
|
||||
{
|
||||
dpl = (desc >> 13) & 3; /*Check permissions*/
|
||||
if (dpl < CPL || dpl < (sel & 3)) valid = 0;
|
||||
}
|
||||
if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/
|
||||
if (valid) flags |= Z_FLAG;
|
||||
cycles -= 20;
|
||||
break;
|
||||
case 0x28: /*VERW*/
|
||||
sel = geteaw(); if (abrt) return 0;
|
||||
flags_rebuild();
|
||||
flags &= ~Z_FLAG;
|
||||
if (!(sel & 0xfffc)) return 0; /*Null selector*/
|
||||
cpl_override = 1;
|
||||
valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
|
||||
desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4);
|
||||
cpl_override = 0; if (abrt) return 0;
|
||||
if (!(desc & 0x1000)) valid = 0;
|
||||
dpl = (desc >> 13) & 3; /*Check permissions*/
|
||||
if (dpl < CPL || dpl < (sel & 3)) valid = 0;
|
||||
if (desc & 0x0800) valid = 0; /*Code*/
|
||||
if (!(desc & 0x0200)) valid = 0; /*Read-only data*/
|
||||
if (valid) flags |= Z_FLAG;
|
||||
cycles -= 20;
|
||||
break;
|
||||
|
||||
default:
|
||||
pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38);
|
||||
pc -= 3;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline op0F00_a16(uint32_t fetchdat)
|
||||
{
|
||||
NOTRM
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
op0F00_common(fetchdat);
|
||||
return 0;
|
||||
}
|
||||
static inline op0F00_a32(uint32_t fetchdat)
|
||||
{
|
||||
NOTRM
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
op0F00_common(fetchdat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline op0F01_common(uint32_t fetchdat, int is32)
|
||||
{
|
||||
uint32_t base;
|
||||
uint16_t limit, tempw;
|
||||
// pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc);
|
||||
switch (rmdat & 0x38)
|
||||
{
|
||||
case 0x00: /*SGDT*/
|
||||
seteaw(gdt.limit);
|
||||
base = is32 ? gdt.base : (gdt.base & 0xffffff);
|
||||
writememl(easeg, eaaddr + 2, base);
|
||||
cycles -= 7;
|
||||
break;
|
||||
case 0x08: /*SIDT*/
|
||||
seteaw(idt.limit);
|
||||
base = is32 ? idt.base : (idt.base & 0xffffff);
|
||||
writememl(easeg, eaaddr + 2, base);
|
||||
cycles -= 7;
|
||||
break;
|
||||
case 0x10: /*LGDT*/
|
||||
if ((CPL || eflags&VM_FLAG) && (cr0&1))
|
||||
{
|
||||
pclog("Invalid LGDT!\n");
|
||||
x86gpf(NULL,0);
|
||||
break;
|
||||
}
|
||||
// pclog("LGDT %08X:%08X\n", easeg, eaaddr);
|
||||
limit = geteaw();
|
||||
base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0;
|
||||
// pclog(" %08X %04X\n", base, limit);
|
||||
gdt.limit = limit;
|
||||
gdt.base = base;
|
||||
if (!is32) gdt.base &= 0xffffff;
|
||||
cycles -= 11;
|
||||
break;
|
||||
case 0x18: /*LIDT*/
|
||||
if ((CPL || eflags&VM_FLAG) && (cr0&1))
|
||||
{
|
||||
pclog("Invalid LIDT!\n");
|
||||
x86gpf(NULL,0);
|
||||
break;
|
||||
}
|
||||
// pclog("LIDT %08X:%08X\n", easeg, eaaddr);
|
||||
limit = geteaw();
|
||||
base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0;
|
||||
// pclog(" %08X %04X\n", base, limit);
|
||||
idt.limit = limit;
|
||||
idt.base = base;
|
||||
if (!is32) idt.base &= 0xffffff;
|
||||
cycles -= 11;
|
||||
break;
|
||||
|
||||
case 0x20: /*SMSW*/
|
||||
if (is486) seteaw(msw);
|
||||
else seteaw(msw | 0xFF00);
|
||||
cycles -= 2;
|
||||
break;
|
||||
case 0x30: /*LMSW*/
|
||||
if ((CPL || eflags&VM_FLAG) && (msw&1))
|
||||
{
|
||||
pclog("LMSW - ring not zero!\n");
|
||||
x86gpf(NULL, 0);
|
||||
break;
|
||||
}
|
||||
tempw = geteaw(); if (abrt) return 0;
|
||||
if (msw & 1) tempw |= 1;
|
||||
msw = tempw;
|
||||
break;
|
||||
|
||||
case 0x38: /*INVLPG*/
|
||||
if (is486)
|
||||
{
|
||||
if ((CPL || eflags&VM_FLAG) && (cr0&1))
|
||||
{
|
||||
pclog("Invalid INVLPG!\n");
|
||||
x86gpf(NULL, 0);
|
||||
break;
|
||||
}
|
||||
mmu_invalidate(ds + eaaddr);
|
||||
cycles -= 12;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38);
|
||||
pc -= 3;
|
||||
x86illegal();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline op0F01_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
op0F01_common(fetchdat, 0);
|
||||
return 0;
|
||||
}
|
||||
static inline op0F01_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
op0F01_common(fetchdat, 0);
|
||||
return 0;
|
||||
}
|
||||
static inline op0F01_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_16(fetchdat);
|
||||
|
||||
op0F01_common(fetchdat, 1);
|
||||
return 0;
|
||||
}
|
||||
static inline op0F01_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
fetch_ea_32(fetchdat);
|
||||
|
||||
op0F01_common(fetchdat, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
73
src/x86_ops_prefix.h
Normal file
73
src/x86_ops_prefix.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
static int op_CS(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
ds = ss = cs;
|
||||
rds = CS;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
static int op_DS(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
ds = ss = ds;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
static int op_ES(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
ds = ss = es;
|
||||
rds = ES;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
static int op_FS(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
rds = FS;
|
||||
ds = ss = fs;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
static int op_GS(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
rds = GS;
|
||||
ds = ss = gs;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
static int op_SS(uint32_t fetchdat)
|
||||
{
|
||||
oldss = ss;
|
||||
oldds = ds;
|
||||
ds = ss = ss;
|
||||
rds = SS;
|
||||
ssegs = 2;
|
||||
cycles -= 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int op_66(uint32_t fetchdat) /*Data size select*/
|
||||
{
|
||||
op32 = ((use32 & 0x100) ^ 0x100) | (op32 & 0x200);
|
||||
cycles -= 2;
|
||||
return 1;
|
||||
}
|
||||
static int op_67(uint32_t fetchdat) /*Address size select*/
|
||||
{
|
||||
op32 = ((use32 & 0x200) ^ 0x200) | (op32 & 0x100);
|
||||
cycles -= 2;
|
||||
return 1;
|
||||
}
|
||||
11
src/x86_ops_rep.h
Normal file
11
src/x86_ops_rep.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
static int opREPNE(uint32_t fetchdat)
|
||||
{
|
||||
rep386(0);
|
||||
return 0;
|
||||
}
|
||||
static int opREPE(uint32_t fetchdat)
|
||||
{
|
||||
rep386(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
152
src/x86_ops_ret.h
Normal file
152
src/x86_ops_ret.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#define RETF_a16(stack_offset) \
|
||||
if ((msw&1) && !(eflags&VM_FLAG)) \
|
||||
{ \
|
||||
pmoderetf(0, stack_offset); \
|
||||
return 0; \
|
||||
} \
|
||||
if (ssegs) ss = oldss; \
|
||||
oxpc = pc; \
|
||||
if (stack32) \
|
||||
{ \
|
||||
pc = readmemw(ss, ESP); \
|
||||
loadcs(readmemw(ss, ESP + 2)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pc = readmemw(ss, SP); \
|
||||
loadcs(readmemw(ss, SP + 2)); \
|
||||
} \
|
||||
if (abrt) return 0; \
|
||||
if (stack32) ESP += 4 + stack_offset; \
|
||||
else SP += 4 + stack_offset; \
|
||||
cycles -= is486 ? 13 : 18;
|
||||
|
||||
#define RETF_a32(stack_offset) \
|
||||
if ((msw&1) && !(eflags&VM_FLAG)) \
|
||||
{ \
|
||||
pmoderetf(1, stack_offset); \
|
||||
return 0; \
|
||||
} \
|
||||
if (ssegs) ss = oldss; \
|
||||
oxpc = pc; \
|
||||
if (stack32) \
|
||||
{ \
|
||||
pc = readmeml(ss, ESP); \
|
||||
loadcs(readmeml(ss, ESP + 4) & 0xffff); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pc = readmeml(ss, SP); \
|
||||
loadcs(readmeml(ss, SP + 4) & 0xffff); \
|
||||
} \
|
||||
if (abrt) return 0; \
|
||||
if (stack32) ESP += 8 + stack_offset; \
|
||||
else SP += 8 + stack_offset; \
|
||||
cycles -= is486 ? 13 : 18;
|
||||
|
||||
static int opRETF_a16(uint32_t fetchdat)
|
||||
{
|
||||
RETF_a16(0);
|
||||
return 0;
|
||||
}
|
||||
static int opRETF_a32(uint32_t fetchdat)
|
||||
{
|
||||
RETF_a32(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opRETF_a16_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
RETF_a16(offset);
|
||||
return 0;
|
||||
}
|
||||
static int opRETF_a32_imm(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
RETF_a32(offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIRET(uint32_t fetchdat)
|
||||
{
|
||||
if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
if (ssegs) ss = oldss;
|
||||
if (msw&1)
|
||||
{
|
||||
optype = IRET;
|
||||
pmodeiret(0);
|
||||
optype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t new_cs;
|
||||
oxpc = pc;
|
||||
if (stack32)
|
||||
{
|
||||
pc = readmemw(ss, ESP);
|
||||
new_cs = readmemw(ss, ESP + 2);
|
||||
flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2;
|
||||
ESP += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = readmemw(ss, SP);
|
||||
new_cs = readmemw(ss, ((SP + 2) & 0xffff));
|
||||
flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2;
|
||||
SP += 6;
|
||||
}
|
||||
loadcs(new_cs);
|
||||
}
|
||||
flags_extract();
|
||||
cycles -= is486 ? 15 : 22;
|
||||
nmi_enable = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opIRETD(uint32_t fetchdat)
|
||||
{
|
||||
if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3))
|
||||
{
|
||||
x86gpf(NULL,0);
|
||||
return 0;
|
||||
}
|
||||
if (ssegs) ss = oldss;
|
||||
if (msw & 1)
|
||||
{
|
||||
optype = IRET;
|
||||
pmodeiret(1);
|
||||
optype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t new_cs;
|
||||
oxpc = pc;
|
||||
if (stack32)
|
||||
{
|
||||
pc = readmeml(ss, ESP);
|
||||
new_cs = readmemw(ss, ESP + 4);
|
||||
flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2;
|
||||
eflags = readmemw(ss, ESP + 10);
|
||||
ESP += 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = readmeml(ss, SP);
|
||||
new_cs = readmemw(ss, ((SP + 4) & 0xffff));
|
||||
flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2;
|
||||
eflags = readmemw(ss, (SP + 10) & 0xffff);
|
||||
SP += 12;
|
||||
}
|
||||
loadcs(new_cs);
|
||||
}
|
||||
flags_extract();
|
||||
cycles -= is486 ? 15 : 22;
|
||||
nmi_enable = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
33
src/x86_ops_set.h
Normal file
33
src/x86_ops_set.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#define opSET(condition) \
|
||||
static int opSET ## condition ## _a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
fetch_ea_16(fetchdat); \
|
||||
seteab((cond_ ## condition) ? 1 : 0); \
|
||||
cycles -= 4; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static int opSET ## condition ## _a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
fetch_ea_32(fetchdat); \
|
||||
seteab((cond_ ## condition) ? 1 : 0); \
|
||||
cycles -= 4; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opSET(O)
|
||||
opSET(NO)
|
||||
opSET(B)
|
||||
opSET(NB)
|
||||
opSET(E)
|
||||
opSET(NE)
|
||||
opSET(BE)
|
||||
opSET(NBE)
|
||||
opSET(S)
|
||||
opSET(NS)
|
||||
opSET(P)
|
||||
opSET(NP)
|
||||
opSET(L)
|
||||
opSET(NL)
|
||||
opSET(LE)
|
||||
opSET(NLE)
|
||||
595
src/x86_ops_shift.h
Normal file
595
src/x86_ops_shift.h
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
#define OP_SHIFT_b(c) \
|
||||
if (!c) return 0; \
|
||||
flags_rebuild(); \
|
||||
switch (rmdat & 0x38) \
|
||||
{ \
|
||||
case 0x00: /*ROL b, c*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = (temp & 0x80) ? 1 : 0; \
|
||||
temp = (temp << 1) | temp2; \
|
||||
c--; \
|
||||
} \
|
||||
seteab(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x08: /*ROR b,CL*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = temp & 1; \
|
||||
temp >>= 1; \
|
||||
if (temp2) temp |= 0x80; \
|
||||
c--; \
|
||||
} \
|
||||
seteab(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x10: /*RCL b,CL*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 1 : 0; \
|
||||
temp2 = temp & 0x80; \
|
||||
temp = (temp << 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteab(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x18: /*RCR b,CL*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 0x80 : 0; \
|
||||
temp2 = temp & 1; \
|
||||
temp = (temp >> 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteab(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x20: case 0x30: /*SHL b,CL*/ \
|
||||
seteab(temp << c); if (abrt) return 0; \
|
||||
setznp8(temp << c); \
|
||||
if ((temp << (c - 1)) & 0x80) flags |= C_FLAG; \
|
||||
if (((temp << c) ^ (temp << (c - 1))) & 0x80) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x28: /*SHR b,CL*/ \
|
||||
seteab(temp >> c); if (abrt) return 0; \
|
||||
setznp8(temp >> c); \
|
||||
if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \
|
||||
if (c == 1 && temp & 0x80) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x38: /*SAR b,CL*/ \
|
||||
tempc = ((temp >> (c - 1)) & 1); \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp >>= 1; \
|
||||
if (temp & 0x40) temp |= 0x80; \
|
||||
c--; \
|
||||
} \
|
||||
seteab(temp); if (abrt) return 0; \
|
||||
setznp8(temp); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define OP_SHIFT_w(c) \
|
||||
if (!c) return 0; \
|
||||
flags_rebuild(); \
|
||||
switch (rmdat & 0x38) \
|
||||
{ \
|
||||
case 0x00: /*ROL w, c*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = (temp & 0x8000) ? 1 : 0; \
|
||||
temp = (temp << 1) | temp2; \
|
||||
c--; \
|
||||
} \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x08: /*ROR w, c*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = temp & 1; \
|
||||
temp >>= 1; \
|
||||
if (temp2) temp |= 0x8000; \
|
||||
c--; \
|
||||
} \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x10: /*RCL w, c*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 1 : 0; \
|
||||
temp2 = temp & 0x8000; \
|
||||
temp = (temp << 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x18: /*RCR w, c*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 0x8000 : 0; \
|
||||
temp2 = temp & 1; \
|
||||
temp = (temp >> 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x20: case 0x30: /*SHL w, c*/ \
|
||||
seteaw(temp << c); if (abrt) return 0; \
|
||||
setznp16(temp << c); \
|
||||
if ((temp << (c - 1)) & 0x8000) flags |= C_FLAG; \
|
||||
if (((temp << c) ^ (temp << (c - 1))) & 0x8000) flags |= V_FLAG;\
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x28: /*SHR w, c*/ \
|
||||
seteaw(temp >> c); if (abrt) return 0; \
|
||||
setznp16(temp >> c); \
|
||||
if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \
|
||||
if (c == 1 && temp & 0x8000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x38: /*SAR w, c*/ \
|
||||
tempc = ((temp >> (c - 1)) & 1); \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp >>= 1; \
|
||||
if (temp & 0x4000) temp |= 0x8000; \
|
||||
c--; \
|
||||
} \
|
||||
seteaw(temp); if (abrt) return 0; \
|
||||
setznp16(temp); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define OP_SHIFT_l(c) \
|
||||
if (!c) return 0; \
|
||||
flags_rebuild(); \
|
||||
switch (rmdat & 0x38) \
|
||||
{ \
|
||||
case 0x00: /*ROL l, c*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = (temp & 0x80000000) ? 1 : 0; \
|
||||
temp = (temp << 1) | temp2; \
|
||||
c--; \
|
||||
} \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x08: /*ROR l, c*/ \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp2 = temp & 1; \
|
||||
temp >>= 1; \
|
||||
if (temp2) temp |= 0x80000000; \
|
||||
c--; \
|
||||
} \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x10: /*RCL l, c*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 1 : 0; \
|
||||
temp2 = temp & 0x80000000; \
|
||||
temp = (temp << 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x18: /*RCR l, c*/ \
|
||||
temp2 = flags & C_FLAG; \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
tempc = temp2 ? 0x80000000 : 0; \
|
||||
temp2 = temp & 1; \
|
||||
temp = (temp >> 1) | tempc; \
|
||||
c--; \
|
||||
if (is486) cycles--; \
|
||||
} \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
flags &= ~(C_FLAG | V_FLAG); \
|
||||
if (temp2) flags |= C_FLAG; \
|
||||
if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 9 : 10); \
|
||||
break; \
|
||||
case 0x20: case 0x30: /*SHL l, c*/ \
|
||||
seteal(temp << c); if (abrt) return 0; \
|
||||
setznp32(temp << c); \
|
||||
if ((temp << (c - 1)) & 0x80000000) flags |= C_FLAG; \
|
||||
if (((temp << c) ^ (temp << (c - 1))) & 0x80000000) flags |= V_FLAG;\
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x28: /*SHR l, c*/ \
|
||||
seteal(temp >> c); if (abrt) return 0; \
|
||||
setznp32(temp >> c); \
|
||||
if ((temp >> (c - 1)) & 1) flags |= C_FLAG; \
|
||||
if (c == 1 && temp & 0x80000000) flags |= V_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
case 0x38: /*SAR l, c*/ \
|
||||
tempc = ((temp >> (c - 1)) & 1); \
|
||||
while (c > 0) \
|
||||
{ \
|
||||
temp >>= 1; \
|
||||
if (temp & 0x40000000) temp |= 0x80000000; \
|
||||
c--; \
|
||||
} \
|
||||
seteal(temp); if (abrt) return 0; \
|
||||
setznp32(temp); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
cycles -= ((mod == 3) ? 3 : 7); \
|
||||
break; \
|
||||
}
|
||||
|
||||
static int opC0_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opC0_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opC1_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opC1_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opC1_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
static int opC1_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = readmemb(cs, pc) & 31; pc++;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opD0_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD0_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD1_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD1_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD1_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD1_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c = 1;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opD2_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD2_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint8_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
OP_SHIFT_b(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD3_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD3_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint16_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
OP_SHIFT_w(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD3_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_16(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
static int opD3_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
int c;
|
||||
int tempc;
|
||||
uint32_t temp, temp2;
|
||||
|
||||
fetch_ea_32(fetchdat);
|
||||
c = CL & 31;
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
OP_SHIFT_l(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define SHLD_w() \
|
||||
if (count) \
|
||||
{ \
|
||||
uint16_t tempw = geteaw(); if (abrt) return 0; \
|
||||
int tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \
|
||||
uint32_t templ = (tempw << 16) | regs[reg].w; \
|
||||
if (count <= 16) tempw = templ >> (16 - count); \
|
||||
else tempw = (templ << count) >> 16; \
|
||||
seteaw(tempw); if (abrt) return 0; \
|
||||
setznp16(tempw); \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
}
|
||||
|
||||
#define SHLD_l() \
|
||||
if (count) \
|
||||
{ \
|
||||
uint32_t templ = geteal(); if (abrt) return 0; \
|
||||
int tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \
|
||||
templ = (templ << count) | (regs[reg].l >> (32 - count)); \
|
||||
seteal(templ); if (abrt) return 0; \
|
||||
setznp32(templ); \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
}
|
||||
|
||||
|
||||
#define SHRD_w() \
|
||||
if (count) \
|
||||
{ \
|
||||
uint16_t tempw = geteaw(); if (abrt) return 0; \
|
||||
int tempc = (tempw >> (count - 1)) & 1; \
|
||||
uint32_t templ = tempw | (regs[reg].w << 16); \
|
||||
tempw = templ >> count; \
|
||||
seteaw(tempw); if (abrt) return 0; \
|
||||
setznp16(tempw); \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
}
|
||||
|
||||
#define SHRD_l() \
|
||||
if (count) \
|
||||
{ \
|
||||
uint32_t templ = geteal(); if (abrt) return 0; \
|
||||
int tempc = (templ >> (count - 1)) & 1; \
|
||||
templ = (templ >> count) | (regs[reg].l << (32 - count)); \
|
||||
seteal(templ); if (abrt) return 0; \
|
||||
setznp32(templ); \
|
||||
flags_rebuild(); \
|
||||
if (tempc) flags |= C_FLAG; \
|
||||
}
|
||||
|
||||
#define opSHxD(operation) \
|
||||
static int op ## operation ## _i_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int count; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
count = getbyte() & 31; \
|
||||
operation(); \
|
||||
\
|
||||
cycles -= 3; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## operation ## _CL_a16(uint32_t fetchdat) \
|
||||
{ \
|
||||
int count; \
|
||||
\
|
||||
fetch_ea_16(fetchdat); \
|
||||
count = CL & 31; \
|
||||
operation(); \
|
||||
\
|
||||
cycles -= 3; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## operation ## _i_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int count; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
count = getbyte() & 31; \
|
||||
operation(); \
|
||||
\
|
||||
cycles -= 3; \
|
||||
return 0; \
|
||||
} \
|
||||
static int op ## operation ## _CL_a32(uint32_t fetchdat) \
|
||||
{ \
|
||||
int count; \
|
||||
\
|
||||
fetch_ea_32(fetchdat); \
|
||||
count = CL & 31; \
|
||||
operation(); \
|
||||
\
|
||||
cycles -= 3; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opSHxD(SHLD_w)
|
||||
opSHxD(SHLD_l)
|
||||
opSHxD(SHRD_w)
|
||||
opSHxD(SHRD_l)
|
||||
447
src/x86_ops_stack.h
Normal file
447
src/x86_ops_stack.h
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
#define PUSH_W_OP(reg) \
|
||||
static int opPUSH_ ## reg (uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
PUSH_W(reg); \
|
||||
cycles -= (is486) ? 1 : 2; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define PUSH_L_OP(reg) \
|
||||
static int opPUSH_ ## reg (uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
PUSH_L(reg); \
|
||||
cycles -= (is486) ? 1 : 2; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define POP_W_OP(reg) \
|
||||
static int opPOP_ ## reg (uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
reg = POP_W(); \
|
||||
cycles -= (is486) ? 1 : 4; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define POP_L_OP(reg) \
|
||||
static int opPOP_ ## reg (uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
reg = POP_L(); \
|
||||
cycles -= (is486) ? 1 : 4; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
PUSH_W_OP(AX)
|
||||
PUSH_W_OP(BX)
|
||||
PUSH_W_OP(CX)
|
||||
PUSH_W_OP(DX)
|
||||
PUSH_W_OP(SI)
|
||||
PUSH_W_OP(DI)
|
||||
PUSH_W_OP(BP)
|
||||
PUSH_W_OP(SP)
|
||||
|
||||
PUSH_L_OP(EAX)
|
||||
PUSH_L_OP(EBX)
|
||||
PUSH_L_OP(ECX)
|
||||
PUSH_L_OP(EDX)
|
||||
PUSH_L_OP(ESI)
|
||||
PUSH_L_OP(EDI)
|
||||
PUSH_L_OP(EBP)
|
||||
PUSH_L_OP(ESP)
|
||||
|
||||
POP_W_OP(AX)
|
||||
POP_W_OP(BX)
|
||||
POP_W_OP(CX)
|
||||
POP_W_OP(DX)
|
||||
POP_W_OP(SI)
|
||||
POP_W_OP(DI)
|
||||
POP_W_OP(BP)
|
||||
POP_W_OP(SP)
|
||||
|
||||
POP_L_OP(EAX)
|
||||
POP_L_OP(EBX)
|
||||
POP_L_OP(ECX)
|
||||
POP_L_OP(EDX)
|
||||
POP_L_OP(ESI)
|
||||
POP_L_OP(EDI)
|
||||
POP_L_OP(EBP)
|
||||
POP_L_OP(ESP)
|
||||
|
||||
|
||||
static int opPUSHA_w(uint32_t fetchdat)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememw(ss, ESP - 2, AX);
|
||||
writememw(ss, ESP - 4, CX);
|
||||
writememw(ss, ESP - 6, DX);
|
||||
writememw(ss, ESP - 8, BX);
|
||||
writememw(ss, ESP - 10, SP);
|
||||
writememw(ss, ESP - 12, BP);
|
||||
writememw(ss, ESP - 14, SI);
|
||||
writememw(ss, ESP - 16, DI);
|
||||
if (!abrt) ESP -= 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss, ((SP - 2) & 0xFFFF), AX);
|
||||
writememw(ss, ((SP - 4) & 0xFFFF), CX);
|
||||
writememw(ss, ((SP - 6) & 0xFFFF), DX);
|
||||
writememw(ss, ((SP - 8) & 0xFFFF), BX);
|
||||
writememw(ss, ((SP - 10) & 0xFFFF), SP);
|
||||
writememw(ss, ((SP - 12) & 0xFFFF), BP);
|
||||
writememw(ss, ((SP - 14) & 0xFFFF), SI);
|
||||
writememw(ss, ((SP - 16) & 0xFFFF), DI);
|
||||
if (!abrt) SP -= 16;
|
||||
}
|
||||
cycles -= (is486) ? 11 : 18;
|
||||
return 0;
|
||||
}
|
||||
static int opPUSHA_l(uint32_t fetchdat)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememl(ss, ESP - 4, EAX);
|
||||
writememl(ss, ESP - 8, ECX);
|
||||
writememl(ss, ESP - 12, EDX);
|
||||
writememl(ss, ESP - 16, EBX);
|
||||
writememl(ss, ESP - 20, ESP);
|
||||
writememl(ss, ESP - 24, EBP);
|
||||
writememl(ss, ESP - 28, ESI);
|
||||
writememl(ss, ESP - 32, EDI);
|
||||
if (!abrt) ESP -= 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememl(ss, ((SP - 4) & 0xFFFF), EAX);
|
||||
writememl(ss, ((SP - 8) & 0xFFFF), ECX);
|
||||
writememl(ss, ((SP - 12) & 0xFFFF), EDX);
|
||||
writememl(ss, ((SP - 16) & 0xFFFF), EBX);
|
||||
writememl(ss, ((SP - 20) & 0xFFFF), ESP);
|
||||
writememl(ss, ((SP - 24) & 0xFFFF), EBP);
|
||||
writememl(ss, ((SP - 28) & 0xFFFF), ESI);
|
||||
writememl(ss, ((SP - 32) & 0xFFFF), EDI);
|
||||
if (!abrt) SP -= 32;
|
||||
}
|
||||
cycles -= (is486) ? 11 : 18;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPOPA_w(uint32_t fetchdat)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
DI = readmemw(ss, ESP); if (abrt) return 0;
|
||||
SI = readmemw(ss, ESP + 2); if (abrt) return 0;
|
||||
BP = readmemw(ss, ESP + 4); if (abrt) return 0;
|
||||
BX = readmemw(ss, ESP + 8); if (abrt) return 0;
|
||||
DX = readmemw(ss, ESP + 10); if (abrt) return 0;
|
||||
CX = readmemw(ss, ESP + 12); if (abrt) return 0;
|
||||
AX = readmemw(ss, ESP + 14); if (abrt) return 0;
|
||||
ESP += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
DI = readmemw(ss, ((SP) & 0xFFFF)); if (abrt) return 0;
|
||||
SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (abrt) return 0;
|
||||
BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 0;
|
||||
BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 0;
|
||||
DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (abrt) return 0;
|
||||
CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (abrt) return 0;
|
||||
AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (abrt) return 0;
|
||||
SP += 16;
|
||||
}
|
||||
cycles -= (is486) ? 9 : 24;
|
||||
return 0;
|
||||
}
|
||||
static int opPOPA_l(uint32_t fetchdat)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
EDI = readmeml(ss, ESP); if (abrt) return 0;
|
||||
ESI = readmeml(ss, ESP + 4); if (abrt) return 0;
|
||||
EBP = readmeml(ss, ESP + 8); if (abrt) return 0;
|
||||
EBX = readmeml(ss, ESP + 16); if (abrt) return 0;
|
||||
EDX = readmeml(ss, ESP + 20); if (abrt) return 0;
|
||||
ECX = readmeml(ss, ESP + 24); if (abrt) return 0;
|
||||
EAX = readmeml(ss, ESP + 28); if (abrt) return 0;
|
||||
ESP += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
EDI = readmeml(ss, ((SP) & 0xFFFF)); if (abrt) return 0;
|
||||
ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 0;
|
||||
EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 0;
|
||||
EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (abrt) return 0;
|
||||
EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (abrt) return 0;
|
||||
ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (abrt) return 0;
|
||||
EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (abrt) return 0;
|
||||
SP += 32;
|
||||
}
|
||||
cycles -= (is486) ? 9 : 24;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPUSH_imm_w(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t val = getwordf();
|
||||
if (ssegs) ss=oldss;
|
||||
PUSH_W(val);
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opPUSH_imm_l(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t val = getlong();
|
||||
if (ssegs) ss=oldss;
|
||||
PUSH_L(val);
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPUSH_imm_bw(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t tempw = getbytef();
|
||||
|
||||
if (tempw & 0x80) tempw |= 0xFF00;
|
||||
PUSH_W(tempw);
|
||||
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
static int opPUSH_imm_bl(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t templ = getbytef();
|
||||
|
||||
if (templ & 0x80) templ |= 0xFFFFFF00;
|
||||
PUSH_L(templ);
|
||||
|
||||
cycles -= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPOPW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
temp = POP_W(); if (abrt) return 0;
|
||||
fetch_ea_16(fetchdat);
|
||||
seteaw(temp);
|
||||
if (abrt)
|
||||
{
|
||||
if (stack32) ESP -= 2;
|
||||
else SP -= 2;
|
||||
}
|
||||
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 6);
|
||||
else cycles -= ((mod == 3) ? 4 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opPOPW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
temp = POP_W(); if (abrt) return 0;
|
||||
fetch_ea_32(fetchdat);
|
||||
seteaw(temp);
|
||||
if (abrt)
|
||||
{
|
||||
if (stack32) ESP -= 2;
|
||||
else SP -= 2;
|
||||
}
|
||||
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 6);
|
||||
else cycles -= ((mod == 3) ? 4 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opPOPL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
temp = POP_L(); if (abrt) return 0;
|
||||
fetch_ea_16(fetchdat);
|
||||
seteal(temp);
|
||||
if (abrt)
|
||||
{
|
||||
if (stack32) ESP -= 4;
|
||||
else SP -= 4;
|
||||
}
|
||||
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 6);
|
||||
else cycles -= ((mod == 3) ? 4 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opPOPL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
if (ssegs) ss=oldss;
|
||||
temp = POP_L(); if (abrt) return 0;
|
||||
fetch_ea_32(fetchdat);
|
||||
seteal(temp);
|
||||
if (abrt)
|
||||
{
|
||||
if (stack32) ESP -= 4;
|
||||
else SP -= 4;
|
||||
}
|
||||
|
||||
if (is486) cycles -= ((mod == 3) ? 1 : 6);
|
||||
else cycles -= ((mod == 3) ? 4 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opENTER_w(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
int count = (fetchdat >> 16) & 0xff; pc++;
|
||||
uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr;
|
||||
|
||||
PUSH_W(BP);
|
||||
frame_ptr = ESP;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
while (--count)
|
||||
{
|
||||
uint16_t tempw;
|
||||
|
||||
BP -= 2;
|
||||
tempw = readmemw(ss, BP);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
PUSH_W(tempw);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
cycles -= (is486) ? 3 : 4;
|
||||
}
|
||||
PUSH_W(frame_ptr);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
cycles -= (is486) ? 3 : 5;
|
||||
}
|
||||
BP = frame_ptr;
|
||||
|
||||
if (stack32) ESP -= offset;
|
||||
else SP -= offset;
|
||||
cycles -= (is486) ? 14 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opENTER_l(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t offset = getwordf();
|
||||
int count = (fetchdat >> 16) & 0xff; pc++;
|
||||
uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr;
|
||||
|
||||
PUSH_L(EBP);
|
||||
frame_ptr = ESP;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
while (--count)
|
||||
{
|
||||
uint32_t templ;
|
||||
|
||||
EBP -= 4;
|
||||
templ = readmeml(ss, EBP);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
PUSH_L(templ);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
cycles -= (is486) ? 3 : 4;
|
||||
}
|
||||
PUSH_L(frame_ptr);
|
||||
if (abrt) { ESP = tempESP; EBP = tempEBP; return 0; }
|
||||
cycles -= (is486) ? 3 : 5;
|
||||
}
|
||||
EBP = frame_ptr;
|
||||
|
||||
if (stack32) ESP -= offset;
|
||||
else SP -= offset;
|
||||
cycles -= (is486) ? 14 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opLEAVE_w(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t tempESP = ESP;
|
||||
uint16_t temp;
|
||||
|
||||
SP = BP;
|
||||
temp = POP_W();
|
||||
if (abrt) { ESP = tempESP; return 0; }
|
||||
BP = temp;
|
||||
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
static int opLEAVE_l(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t tempESP = ESP;
|
||||
uint32_t temp;
|
||||
|
||||
ESP = EBP;
|
||||
temp = POP_L();
|
||||
if (abrt) { ESP = tempESP; return 0; }
|
||||
EBP = temp;
|
||||
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define PUSH_SEG_OPS(seg) \
|
||||
static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
PUSH_W(seg); \
|
||||
cycles -= 2; \
|
||||
return 0; \
|
||||
} \
|
||||
static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \
|
||||
{ \
|
||||
if (ssegs) ss=oldss; \
|
||||
PUSH_L(seg); \
|
||||
cycles -= 2; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define POP_SEG_OPS(seg, realseg) \
|
||||
static int opPOP_ ## seg ## _w(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint16_t temp_seg; \
|
||||
uint32_t temp_esp = ESP; \
|
||||
if (ssegs) ss=oldss; \
|
||||
temp_seg = POP_W(); if (abrt) return 0; \
|
||||
loadseg(temp_seg, realseg); if (abrt) ESP = temp_esp; \
|
||||
cycles -= is486 ? 3 : 7; \
|
||||
return 0; \
|
||||
} \
|
||||
static int opPOP_ ## seg ## _l(uint32_t fetchdat) \
|
||||
{ \
|
||||
uint32_t temp_seg; \
|
||||
uint32_t temp_esp = ESP; \
|
||||
if (ssegs) ss=oldss; \
|
||||
temp_seg = POP_L(); if (abrt) return 0; \
|
||||
loadseg(temp_seg & 0xffff, realseg); if (abrt) ESP = temp_esp; \
|
||||
cycles -= is486 ? 3 : 7; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
PUSH_SEG_OPS(CS);
|
||||
PUSH_SEG_OPS(DS);
|
||||
PUSH_SEG_OPS(ES);
|
||||
PUSH_SEG_OPS(FS);
|
||||
PUSH_SEG_OPS(GS);
|
||||
PUSH_SEG_OPS(SS);
|
||||
|
||||
POP_SEG_OPS(DS, &_ds);
|
||||
POP_SEG_OPS(ES, &_es);
|
||||
POP_SEG_OPS(FS, &_fs);
|
||||
POP_SEG_OPS(GS, &_gs);
|
||||
POP_SEG_OPS(SS, &_ss);
|
||||
435
src/x86_ops_string.h
Normal file
435
src/x86_ops_string.h
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
static int opMOVSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds,SI); if (abrt) return 0;
|
||||
writememb(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { DI--; SI--; }
|
||||
else { DI++; SI++; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds,ESI); if (abrt) return 0;
|
||||
writememb(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { EDI--; ESI--; }
|
||||
else { EDI++; ESI++; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOVSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds,SI); if (abrt) return 0;
|
||||
writememw(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { DI -= 2; SI -= 2; }
|
||||
else { DI += 2; SI += 2; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds,ESI); if (abrt) return 0;
|
||||
writememw(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { EDI -= 2; ESI -= 2; }
|
||||
else { EDI += 2; ESI += 2; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opMOVSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds,SI); if (abrt) return 0;
|
||||
writememl(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { DI -= 4; SI -= 4; }
|
||||
else { DI += 4; SI += 4; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opMOVSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds,ESI); if (abrt) return 0;
|
||||
writememl(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) { EDI -= 4; ESI -= 4; }
|
||||
else { EDI += 4; ESI += 4; }
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opCMPSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src = readmemb(ds, SI);
|
||||
uint8_t dst = readmemb(es, DI); if (abrt) return 0;
|
||||
setsub8(src, dst);
|
||||
if (flags & D_FLAG) { DI--; SI--; }
|
||||
else { DI++; SI++; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t src = readmemb(ds, ESI);
|
||||
uint8_t dst = readmemb(es, EDI); if (abrt) return 0;
|
||||
setsub8(src, dst);
|
||||
if (flags & D_FLAG) { EDI--; ESI--; }
|
||||
else { EDI++; ESI++; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMPSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src = readmemw(ds, SI);
|
||||
uint16_t dst = readmemw(es, DI); if (abrt) return 0;
|
||||
setsub16(src, dst);
|
||||
if (flags & D_FLAG) { DI -= 2; SI -= 2; }
|
||||
else { DI += 2; SI += 2; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t src = readmemw(ds, ESI);
|
||||
uint16_t dst = readmemw(es, EDI); if (abrt) return 0;
|
||||
setsub16(src, dst);
|
||||
if (flags & D_FLAG) { EDI -= 2; ESI -= 2; }
|
||||
else { EDI += 2; ESI += 2; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opCMPSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src = readmeml(ds, SI);
|
||||
uint32_t dst = readmeml(es, DI); if (abrt) return 0;
|
||||
setsub32(src, dst);
|
||||
if (flags & D_FLAG) { DI -= 4; SI -= 4; }
|
||||
else { DI += 4; SI += 4; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
static int opCMPSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t src = readmeml(ds, ESI);
|
||||
uint32_t dst = readmeml(es, EDI); if (abrt) return 0;
|
||||
setsub32(src, dst);
|
||||
if (flags & D_FLAG) { EDI -= 4; ESI -= 4; }
|
||||
else { EDI += 4; ESI += 4; }
|
||||
cycles -= (is486) ? 8 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSTOSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
writememb(es, DI, AL); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI--;
|
||||
else DI++;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
static int opSTOSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
writememb(es, EDI, AL); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI--;
|
||||
else EDI++;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSTOSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
writememw(es, DI, AX); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI -= 2;
|
||||
else DI += 2;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
static int opSTOSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
writememw(es, EDI, AX); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI -= 2;
|
||||
else EDI += 2;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSTOSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
writememl(es, DI, EAX); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI -= 4;
|
||||
else DI += 4;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
static int opSTOSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
writememl(es, EDI, EAX); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI -= 4;
|
||||
else EDI += 4;
|
||||
cycles -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opLODSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds, SI); if (abrt) return 0;
|
||||
AL = temp;
|
||||
if (flags & D_FLAG) SI--;
|
||||
else SI++;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opLODSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds, ESI); if (abrt) return 0;
|
||||
AL = temp;
|
||||
if (flags & D_FLAG) ESI--;
|
||||
else ESI++;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLODSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds, SI); if (abrt) return 0;
|
||||
AX = temp;
|
||||
if (flags & D_FLAG) SI -= 2;
|
||||
else SI += 2;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opLODSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds, ESI); if (abrt) return 0;
|
||||
AX = temp;
|
||||
if (flags & D_FLAG) ESI -= 2;
|
||||
else ESI += 2;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opLODSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds, SI); if (abrt) return 0;
|
||||
EAX = temp;
|
||||
if (flags & D_FLAG) SI -= 4;
|
||||
else SI += 4;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
static int opLODSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds, ESI); if (abrt) return 0;
|
||||
EAX = temp;
|
||||
if (flags & D_FLAG) ESI -= 4;
|
||||
else ESI += 4;
|
||||
cycles -= 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opSCASB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(es, DI); if (abrt) return 0;
|
||||
setsub8(AL, temp);
|
||||
if (flags & D_FLAG) DI--;
|
||||
else DI++;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opSCASB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(es, EDI); if (abrt) return 0;
|
||||
setsub8(AL, temp);
|
||||
if (flags & D_FLAG) EDI--;
|
||||
else EDI++;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSCASW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(es, DI); if (abrt) return 0;
|
||||
setsub16(AX, temp);
|
||||
if (flags & D_FLAG) DI -= 2;
|
||||
else DI += 2;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opSCASW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(es, EDI); if (abrt) return 0;
|
||||
setsub16(AX, temp);
|
||||
if (flags & D_FLAG) EDI -= 2;
|
||||
else EDI += 2;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opSCASL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(es, DI); if (abrt) return 0;
|
||||
setsub32(EAX, temp);
|
||||
if (flags & D_FLAG) DI -= 4;
|
||||
else DI += 4;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
static int opSCASL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(es, EDI); if (abrt) return 0;
|
||||
setsub32(EAX, temp);
|
||||
if (flags & D_FLAG) EDI -= 4;
|
||||
else EDI += 4;
|
||||
cycles -= 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
check_io_perm(DX);
|
||||
temp = inb(DX);
|
||||
writememb(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI--;
|
||||
else DI++;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
static int opINSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
check_io_perm(DX);
|
||||
temp = inb(DX);
|
||||
writememb(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI--;
|
||||
else EDI++;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
temp = inw(DX);
|
||||
writememw(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI -= 2;
|
||||
else DI += 2;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
static int opINSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
temp = inw(DX);
|
||||
writememw(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI -= 2;
|
||||
else EDI += 2;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opINSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
temp = inl(DX);
|
||||
writememl(es, DI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) DI -= 4;
|
||||
else DI += 4;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
static int opINSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
temp = inl(DX);
|
||||
writememl(es, EDI, temp); if (abrt) return 0;
|
||||
if (flags & D_FLAG) EDI -= 4;
|
||||
else EDI += 4;
|
||||
cycles -= 15;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opOUTSB_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds, SI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
if (flags & D_FLAG) SI--;
|
||||
else SI++;
|
||||
outb(DX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
static int opOUTSB_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp = readmemb(ds, ESI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
if (flags & D_FLAG) ESI--;
|
||||
else ESI++;
|
||||
outb(DX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opOUTSW_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds, SI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
if (flags & D_FLAG) SI -= 2;
|
||||
else SI += 2;
|
||||
outw(DX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
static int opOUTSW_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = readmemw(ds, ESI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
if (flags & D_FLAG) ESI -= 2;
|
||||
else ESI += 2;
|
||||
outw(DX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opOUTSL_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds, SI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
if (flags & D_FLAG) SI -= 4;
|
||||
else SI += 4;
|
||||
outl(EDX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
static int opOUTSL_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = readmeml(ds, ESI); if (abrt) return 0;
|
||||
check_io_perm(DX);
|
||||
check_io_perm(DX + 1);
|
||||
check_io_perm(DX + 2);
|
||||
check_io_perm(DX + 3);
|
||||
if (flags & D_FLAG) ESI -= 4;
|
||||
else ESI += 4;
|
||||
outl(EDX, temp);
|
||||
cycles -= 14;
|
||||
return 0;
|
||||
}
|
||||
195
src/x86_ops_xchg.h
Normal file
195
src/x86_ops_xchg.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
static int opXCHG_b_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
seteab(getr8(reg)); if (abrt) return 0;
|
||||
setr8(reg, temp);
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_b_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint8_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteab(); if (abrt) return 0;
|
||||
seteab(getr8(reg)); if (abrt) return 0;
|
||||
setr8(reg, temp);
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXCHG_w_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(regs[reg].w); if (abrt) return 0;
|
||||
regs[reg].w = temp;
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_w_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteaw(); if (abrt) return 0;
|
||||
seteaw(regs[reg].w); if (abrt) return 0;
|
||||
regs[reg].w = temp;
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXCHG_l_a16(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_16(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(regs[reg].l); if (abrt) return 0;
|
||||
regs[reg].l = temp;
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_l_a32(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp;
|
||||
fetch_ea_32(fetchdat);
|
||||
temp = geteal(); if (abrt) return 0;
|
||||
seteal(regs[reg].l); if (abrt) return 0;
|
||||
regs[reg].l = temp;
|
||||
cycles -= ((mod == 3) ? 3 : 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int opXCHG_AX_BX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = BX;
|
||||
BX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_CX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = CX;
|
||||
CX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_DX(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = DX;
|
||||
DX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_SI(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = SI;
|
||||
SI = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_DI(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = DI;
|
||||
DI = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_BP(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = BP;
|
||||
BP = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_AX_SP(uint32_t fetchdat)
|
||||
{
|
||||
uint16_t temp = AX;
|
||||
AX = SP;
|
||||
SP = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opXCHG_EAX_EBX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = EBX;
|
||||
EBX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_ECX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = ECX;
|
||||
ECX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_EDX(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = EDX;
|
||||
EDX = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_ESI(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = ESI;
|
||||
ESI = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_EDI(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = EDI;
|
||||
EDI = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_EBP(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = EBP;
|
||||
EBP = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
static int opXCHG_EAX_ESP(uint32_t fetchdat)
|
||||
{
|
||||
uint32_t temp = EAX;
|
||||
EAX = ESP;
|
||||
ESP = temp;
|
||||
cycles -= 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define opBSWAP(reg) \
|
||||
static int opBSWAP_ ## reg(uint32_t fetchdat) \
|
||||
{ \
|
||||
reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \
|
||||
cycles--; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
opBSWAP(EAX)
|
||||
opBSWAP(EBX)
|
||||
opBSWAP(ECX)
|
||||
opBSWAP(EDX)
|
||||
opBSWAP(ESI)
|
||||
opBSWAP(EDI)
|
||||
opBSWAP(EBP)
|
||||
opBSWAP(ESP)
|
||||
Loading…
Reference in a new issue