This commit is contained in:
twinaphex 2018-01-02 17:43:28 +01:00
commit 5e08d51b4b
42 changed files with 707 additions and 456 deletions

View File

@ -44,6 +44,9 @@ asm_mix ?= 1
else # if not arm
use_fame ?= 1
use_cz80 ?= 1
ifneq (,$(findstring 86,$(ARCH)))
use_sh2drc ?= 1
endif
endif
-include Makefile.local
@ -66,7 +69,13 @@ endif
ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","rpi1" "rpi2"))
CFLAGS += -DHAVE_GLES -DRASPBERRY
CFLAGS += -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads/ -I/opt/vc/include/interface/vmcs_host/linux/
LDFLAGS += -ldl -lbcm_host -L/opt/vc/lib -lEGL -lGLESv2
LDFLAGS += -ldl -lbcm_host -L/opt/vc/lib
# Stupid renaming occured in latest raspbian...
ifneq (,$(wildcard /opt/vc/lib/libbrcmGLESv2.so))
LDFLAGS += -lbrcmEGL -lbrcmGLESv2
else
LDFLAGS += -lEGL -lGLESv2
endif
OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME
OBJS += platform/common/plat_sdl.o
OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o
@ -221,8 +230,9 @@ pico/carthw_cfg.c: pico/carthw.cfg
tools/make_carthw_c $< $@
# random deps
pico/carthw/svp/compiler.o : cpu/drc/emit_$(ARCH).c
cpu/sh2/compiler.o : cpu/drc/emit_$(ARCH).c
pico/carthw/svp/compiler.o : cpu/drc/emit_arm.c
cpu/sh2/compiler.o : cpu/drc/emit_arm.c
cpu/sh2/compiler.o : cpu/drc/emit_x86.c
cpu/sh2/mame/sh2pico.o : cpu/sh2/mame/sh2.c
pico/pico.o pico/cd/mcd.o pico/32x/32x.o : pico/pico_cmn.c pico/pico_int.h
pico/memory.o pico/cd/memory.o pico/32x/memory.o : pico/pico_int.h pico/memory.h

View File

@ -52,6 +52,7 @@ ifeq ($(platform), unix)
SHARED := -shared
DONT_COMPILE_IN_ZLIB = 1
CFLAGS += -DFAMEC_NO_GOTOS
use_sh2drc = 1
# Portable Linux
else ifeq ($(platform), linux-portable)
@ -62,6 +63,7 @@ else ifeq ($(platform), linux-portable)
LIBM :=
DONT_COMPILE_IN_ZLIB = 1
CFLAGS += -DFAMEC_NO_GOTOS
use_sh2drc = 1
# OS X
else ifeq ($(platform), osx)

7
README
View File

@ -12,10 +12,3 @@ then taken over and expanded by notaz.
PicoDrive was the first emulator ever to properly emulate Virtua Racing and
it's SVP chip.
How to compile on Raspbian Wheezy:
export CC=gcc-4.8
export CXX=g++-4.8
./configure --platform=rpi2
make

View File

@ -1,7 +1,9 @@
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
#define DRC_TCACHE_SIZE (2*1024*1024)

View File

@ -6,6 +6,7 @@
* See COPYING file in the top-level directory.
*/
#define CONTEXT_REG 11
#define RET_REG 0
// XXX: tcache_ptr type for SVP and SH2 compilers differs..
#define EMIT_PTR(ptr, x) \
@ -243,6 +244,11 @@
#define EOP_MSR_IMM(ror2,imm) EOP_C_MSR_IMM(A_COND_AL,ror2,imm)
#define EOP_MSR_REG(rm) EOP_C_MSR_REG(A_COND_AL,rm)
#define EOP_MOVW(rd,imm) \
EMIT(0xe3000000 | ((rd)<<12) | ((imm)&0xfff) | (((imm)<<4)&0xf0000))
#define EOP_MOVT(rd,imm) \
EMIT(0xe3400000 | ((rd)<<12) | (((imm)>>16)&0xfff) | (((imm)>>12)&0xf0000))
// XXX: AND, RSB, *C, will break if 1 insn is not enough
static void emith_op_imm2(int cond, int s, int op, int rd, int rn, unsigned int imm)
@ -257,6 +263,19 @@ static void emith_op_imm2(int cond, int s, int op, int rd, int rn, unsigned int
imm = ~imm;
op = A_OP_MVN;
}
#ifdef HAVE_ARMV7
for (v = imm, ror2 = 0; v && !(v & 3); v >>= 2)
ror2--;
if (v >> 8) {
/* 2+ insns needed - prefer movw/movt */
if (op == A_OP_MVN)
imm = ~imm;
EOP_MOVW(rd, imm);
if (imm & 0xffff0000)
EOP_MOVT(rd, imm);
return;
}
#endif
break;
case A_OP_EOR:
@ -351,6 +370,9 @@ static int emith_xbranch(int cond, void *target, int is_call)
#define EMITH_NOTHING1(cond) \
(void)(cond)
#define EMITH_SJMP_DECL_()
#define EMITH_SJMP_START_(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP_END_(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP_START(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP_END(cond) EMITH_NOTHING1(cond)
#define EMITH_SJMP3_START(cond) EMITH_NOTHING1(cond)
@ -360,6 +382,9 @@ static int emith_xbranch(int cond, void *target, int is_call)
#define emith_move_r_r(d, s) \
EOP_MOV_REG_SIMPLE(d, s)
#define emith_move_r_r_ptr(d, s) \
emith_move_r_r(d, s)
#define emith_mvn_r_r(d, s) \
EOP_MVN_REG(A_COND_AL,0,d,s,A_AM1_LSL,0)
@ -503,6 +528,9 @@ static int emith_xbranch(int cond, void *target, int is_call)
#define emith_add_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_ADD, d, s, imm)
#define emith_add_r_r_ptr_imm(d, s, imm) \
emith_add_r_r_imm(d, s, imm)
#define emith_sub_r_r_imm(d, s, imm) \
emith_op_imm2(A_COND_AL, 0, A_OP_SUB, d, s, imm)
@ -593,6 +621,9 @@ static int emith_xbranch(int cond, void *target, int is_call)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_ptr(r, offs) \
emith_ctx_read(r, offs)
#define emith_ctx_write(r, offs) \
EOP_STR_IMM(r, CONTEXT_REG, offs)

View File

@ -16,6 +16,7 @@
enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define CONTEXT_REG xBP
#define RET_REG xAX
#define ICOND_JO 0x00
#define ICOND_JNO 0x01
@ -53,15 +54,15 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define EMIT_PTR(ptr, val, type) \
*(type *)(ptr) = val
#define EMIT(val, type) { \
#define EMIT(val, type) do { \
EMIT_PTR(tcache_ptr, val, type); \
tcache_ptr += sizeof(type); \
}
} while (0)
#define EMIT_OP(op) { \
#define EMIT_OP(op) do { \
COUNT_OP; \
EMIT(op, u8); \
}
} while (0)
#define EMIT_MODRM(mod,r,rm) \
EMIT(((mod)<<6) | ((r)<<3) | (rm), u8)
@ -69,6 +70,9 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define EMIT_SIB(scale,index,base) \
EMIT(((scale)<<6) | ((index)<<3) | (base), u8)
#define EMIT_REX(w,r,x,b) \
EMIT(0x40 | ((w)<<3) | ((r)<<2) | ((x)<<1) | (b), u8)
#define EMIT_OP_MODRM(op,mod,r,rm) do { \
EMIT_OP(op); \
EMIT_MODRM(mod, r, rm); \
@ -90,6 +94,11 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_move_r_r(dst, src) \
EMIT_OP_MODRM(0x8b, 3, dst, src)
#define emith_move_r_r_ptr(dst, src) do { \
EMIT_REX_FOR_PTR(); \
EMIT_OP_MODRM(0x8b, 3, dst, src); \
} while (0)
#define emith_add_r_r(d, s) \
EMIT_OP_MODRM(0x01, 3, s, d)
@ -118,34 +127,34 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
EMIT_OP_MODRM(0x39, 3, s, d)
// fake teq - test equivalence - get_flags(d ^ s)
#define emith_teq_r_r(d, s) { \
#define emith_teq_r_r(d, s) do { \
emith_push(d); \
emith_eor_r_r(d, s); \
emith_pop(d); \
}
} while (0)
#define emith_mvn_r_r(d, s) { \
#define emith_mvn_r_r(d, s) do { \
if (d != s) \
emith_move_r_r(d, s); \
EMIT_OP_MODRM(0xf7, 3, 2, d); /* NOT d */ \
}
} while (0)
#define emith_negc_r_r(d, s) { \
#define emith_negc_r_r(d, s) do { \
int tmp_ = rcache_get_tmp(); \
emith_move_r_imm(tmp_, 0); \
emith_sbc_r_r(tmp_, s); \
emith_move_r_r(d, tmp_); \
rcache_free_tmp(tmp_); \
}
} while (0)
#define emith_neg_r_r(d, s) { \
#define emith_neg_r_r(d, s) do { \
if (d != s) \
emith_move_r_r(d, s); \
EMIT_OP_MODRM(0xf7, 3, 3, d); /* NEG d */ \
}
} while (0)
// _r_r_r
#define emith_add_r_r_r(d, s1, s2) { \
#define emith_add_r_r_r(d, s1, s2) do { \
if (d == s1) { \
emith_add_r_r(d, s2); \
} else if (d == s2) { \
@ -154,9 +163,9 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_move_r_r(d, s1); \
emith_add_r_r(d, s2); \
} \
}
} while (0)
#define emith_eor_r_r_r(d, s1, s2) { \
#define emith_eor_r_r_r(d, s1, s2) do { \
if (d == s1) { \
emith_eor_r_r(d, s2); \
} else if (d == s2) { \
@ -165,29 +174,29 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_move_r_r(d, s1); \
emith_eor_r_r(d, s2); \
} \
}
} while (0)
// _r_r_shift
#define emith_or_r_r_lsl(d, s, lslimm) { \
#define emith_or_r_r_lsl(d, s, lslimm) do { \
int tmp_ = rcache_get_tmp(); \
emith_lsl(tmp_, s, lslimm); \
emith_or_r_r(d, tmp_); \
rcache_free_tmp(tmp_); \
}
} while (0)
// d != s
#define emith_eor_r_r_lsr(d, s, lsrimm) { \
#define emith_eor_r_r_lsr(d, s, lsrimm) do { \
emith_push(s); \
emith_lsr(s, s, lsrimm); \
emith_eor_r_r(d, s); \
emith_pop(s); \
}
} while (0)
// _r_imm
#define emith_move_r_imm(r, imm) { \
#define emith_move_r_imm(r, imm) do { \
EMIT_OP(0xb8 + (r)); \
EMIT(imm, u32); \
}
} while (0)
#define emith_move_r_imm_s8(r, imm) \
emith_move_r_imm(r, (u32)(signed int)(signed char)(imm))
@ -212,7 +221,14 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_and_r_imm(r, imm) \
emith_arith_r_imm(4, r, imm)
#define emith_sub_r_imm(r, imm) \
/* used for sub cycles after test, so retain flags with lea */
#define emith_sub_r_imm(r, imm) do { \
assert(r != xSP); \
EMIT_OP_MODRM(0x8d, 2, r, r); \
EMIT(-(s32)(imm), s32); \
} while (0)
#define emith_subf_r_imm(r, imm) \
emith_arith_r_imm(5, r, imm)
#define emith_eor_r_imm(r, imm) \
@ -231,20 +247,20 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_arith_r_imm(4, r, ~(imm))
// fake conditionals (using SJMP instead)
#define emith_move_r_imm_c(cond, r, imm) { \
#define emith_move_r_imm_c(cond, r, imm) do { \
(void)(cond); \
emith_move_r_imm(r, imm); \
}
} while (0)
#define emith_add_r_imm_c(cond, r, imm) { \
#define emith_add_r_imm_c(cond, r, imm) do { \
(void)(cond); \
emith_add_r_imm(r, imm); \
}
} while (0)
#define emith_sub_r_imm_c(cond, r, imm) { \
#define emith_sub_r_imm_c(cond, r, imm) do { \
(void)(cond); \
emith_sub_r_imm(r, imm); \
}
} while (0)
#define emith_or_r_imm_c(cond, r, imm) \
emith_or_r_imm(r, imm)
@ -274,26 +290,40 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_ret_c(cond) \
emith_ret()
// _r_r_imm
#define emith_add_r_r_imm(d, s, imm) { \
if (d != s) \
emith_move_r_r(d, s); \
emith_add_r_imm(d, imm); \
}
// _r_r_imm - use lea
#define emith_add_r_r_imm(d, s, imm) do { \
assert(s != xSP); \
EMIT_OP_MODRM(0x8d, 2, d, s); /* lea */ \
EMIT(imm, s32); \
} while (0)
#define emith_and_r_r_imm(d, s, imm) { \
#define emith_add_r_r_ptr_imm(d, s, imm) do { \
if (s != xSP) { \
EMIT_REX_FOR_PTR(); \
EMIT_OP_MODRM(0x8d, 2, d, s); /* lea */ \
} \
else { \
if (d != s) \
emith_move_r_r_ptr(d, s); \
EMIT_REX_FOR_PTR(); \
EMIT_OP_MODRM(0x81, 3, 0, d); /* add */ \
} \
EMIT(imm, s32); \
} while (0)
#define emith_and_r_r_imm(d, s, imm) do { \
if (d != s) \
emith_move_r_r(d, s); \
emith_and_r_imm(d, imm); \
}
} while (0)
// shift
#define emith_shift(op, d, s, cnt) { \
#define emith_shift(op, d, s, cnt) do { \
if (d != s) \
emith_move_r_r(d, s); \
EMIT_OP_MODRM(0xc1, 3, op, d); \
EMIT(cnt, u8); \
}
} while (0)
#define emith_lsl(d, s, cnt) \
emith_shift(4, d, s, cnt)
@ -320,10 +350,10 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_push(r) \
EMIT_OP(0x50 + (r))
#define emith_push_imm(imm) { \
#define emith_push_imm(imm) do { \
EMIT_OP(0x68); \
EMIT(imm, u32); \
}
} while (0)
#define emith_pop(r) \
EMIT_OP(0x58 + (r))
@ -349,13 +379,14 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_asr(d, d, 32 - (bits)); \
}
#define emith_setc(r) { \
#define emith_setc(r) do { \
assert(is_abcdx(r)); \
EMIT_OP(0x0f); \
EMIT_OP_MODRM(0x92, 3, 0, r); /* SETC r */ \
}
} while (0)
// XXX: stupid mess
#define emith_mul_(op, dlo, dhi, s1, s2) { \
#define emith_mul_(op, dlo, dhi, s1, s2) do { \
int rmr; \
if (dlo != xAX && dhi != xAX) \
emith_push(xAX); \
@ -381,7 +412,7 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_pop(xDX); \
if (dlo != xAX && dhi != xAX) \
emith_pop(xAX); \
}
} while (0)
#define emith_mul_u64(dlo, dhi, s1, s2) \
emith_mul_(4, dlo, dhi, s1, s2) /* MUL */
@ -393,20 +424,19 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_mul_(4, d, -1, s1, s2)
// (dlo,dhi) += signed(s1) * signed(s2)
#define emith_mula_s64(dlo, dhi, s1, s2) { \
#define emith_mula_s64(dlo, dhi, s1, s2) do { \
emith_push(dhi); \
emith_push(dlo); \
emith_mul_(5, dlo, dhi, s1, s2); \
EMIT_OP_MODRM(0x03, 0, dlo, 4); \
EMIT_SIB(0, 4, 4); /* add dlo, [esp] */ \
EMIT_SIB(0, 4, 4); /* add dlo, [xsp] */ \
EMIT_OP_MODRM(0x13, 1, dhi, 4); \
EMIT_SIB(0, 4, 4); \
EMIT(4, u8); /* adc dhi, [esp+4] */ \
emith_add_r_imm(xSP, 4*2); \
}
EMIT(sizeof(void *), u8); /* adc dhi, [xsp+{4,8}] */ \
emith_add_r_r_ptr_imm(xSP, xSP, sizeof(void *) * 2); \
} while (0)
// "flag" instructions are the same
#define emith_subf_r_imm emith_sub_r_imm
#define emith_addf_r_r emith_add_r_r
#define emith_subf_r_r emith_sub_r_r
#define emith_adcf_r_r emith_adc_r_r
@ -464,19 +494,24 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
rcache_free_tmp(r_); \
} while (0)
#define emith_read16_r_r_offs(r, rs, offs) { \
#define emith_read16_r_r_offs(r, rs, offs) do { \
EMIT(0x66, u8); /* operand override */ \
emith_read_r_r_offs(r, rs, offs); \
}
} while (0)
#define emith_write16_r_r_offs(r, rs, offs) { \
#define emith_write16_r_r_offs(r, rs, offs) do { \
EMIT(0x66, u8); \
emith_write_r_r_offs(r, rs, offs); \
}
} while (0)
#define emith_ctx_read(r, offs) \
emith_read_r_r_offs(r, CONTEXT_REG, offs)
#define emith_ctx_read_ptr(r, offs) do { \
EMIT_REX_FOR_PTR(); \
emith_deref_op(0x8b, r, CONTEXT_REG, offs); \
} while (0)
#define emith_ctx_write(r, offs) \
emith_write_r_r_offs(r, CONTEXT_REG, offs)
@ -499,7 +534,7 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
}
#define emith_jump(ptr) { \
u32 disp = (u32)(ptr) - ((u32)tcache_ptr + 5); \
u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
EMIT_OP(0xe9); \
EMIT(disp, u32); \
}
@ -507,30 +542,30 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_jump_patchable(target) \
emith_jump(target)
#define emith_jump_cond(cond, ptr) { \
u32 disp = (u32)(ptr) - ((u32)tcache_ptr + 6); \
#define emith_jump_cond(cond, ptr) do { \
u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 6); \
EMIT(0x0f, u8); \
EMIT_OP(0x80 | (cond)); \
EMIT(disp, u32); \
}
} while (0)
#define emith_jump_cond_patchable(cond, target) \
emith_jump_cond(cond, target)
#define emith_jump_patch(ptr, target) do { \
u32 disp_ = (u32)(target) - ((u32)(ptr) + 4); \
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 4); \
u32 offs_ = (*(u8 *)(ptr) == 0x0f) ? 2 : 1; \
EMIT_PTR((u8 *)(ptr) + offs_, disp_ - offs_, u32); \
} while (0)
#define emith_jump_at(ptr, target) { \
u32 disp_ = (u32)(target) - ((u32)(ptr) + 5); \
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 5); \
EMIT_PTR(ptr, 0xe9, u8); \
EMIT_PTR((u8 *)(ptr) + 1, disp_, u32); \
}
#define emith_call(ptr) { \
u32 disp = (u32)(ptr) - ((u32)tcache_ptr + 5); \
u32 disp = (u8 *)(ptr) - ((u8 *)tcache_ptr + 5); \
EMIT_OP(0xe8); \
EMIT(disp, u32); \
}
@ -541,10 +576,10 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_call_reg(r) \
EMIT_OP_MODRM(0xff, 3, 2, r)
#define emith_call_ctx(offs) { \
#define emith_call_ctx(offs) do { \
EMIT_OP_MODRM(0xff, 2, 2, CONTEXT_REG); \
EMIT(offs, u32); \
}
} while (0)
#define emith_ret() \
EMIT_OP(0xc3)
@ -552,10 +587,10 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define emith_jump_reg(r) \
EMIT_OP_MODRM(0xff, 3, 4, r)
#define emith_jump_ctx(offs) { \
#define emith_jump_ctx(offs) do { \
EMIT_OP_MODRM(0xff, 2, 4, CONTEXT_REG); \
EMIT(offs, u32); \
}
} while (0)
#define emith_push_ret()
@ -584,6 +619,15 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
// "simple" jump (no more then a few insns)
// ARM will use conditional instructions here
#define EMITH_SJMP_DECL_() \
u8 *cond_ptr
#define EMITH_SJMP_START_(cond) \
JMP8_POS(cond_ptr)
#define EMITH_SJMP_END_(cond) \
JMP8_EMIT(cond, cond_ptr)
#define EMITH_SJMP_START EMITH_JMP_START
#define EMITH_SJMP_END EMITH_JMP_END
@ -591,20 +635,55 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
#define EMITH_SJMP3_MID EMITH_JMP3_MID
#define EMITH_SJMP3_END EMITH_JMP3_END
#define emith_pass_arg_r(arg, reg) { \
#define emith_pass_arg_r(arg, reg) do { \
int rd = 7; \
host_arg2reg(rd, arg); \
emith_move_r_r(rd, reg); \
}
emith_move_r_r_ptr(rd, reg); \
} while (0)
#define emith_pass_arg_imm(arg, imm) { \
#define emith_pass_arg_imm(arg, imm) do { \
int rd = 7; \
host_arg2reg(rd, arg); \
emith_move_r_imm(rd, imm); \
}
} while (0)
#define host_instructions_updated(base, end)
#ifdef __x86_64__
#define PTR_SCALE 3
#define NA_TMP_REG xCX // non-arg tmp from reg_temp[]
#define EMIT_REX_FOR_PTR() \
EMIT_REX(1,0,0,0)
#define host_arg2reg(rd, arg) \
switch (arg) { \
case 0: rd = xDI; break; \
case 1: rd = xSI; break; \
case 2: rd = xDX; break; \
}
#define emith_sh2_drc_entry() { \
emith_push(xBX); \
emith_push(xBP); \
emith_push(xSI); /* to align */ \
}
#define emith_sh2_drc_exit() { \
emith_pop(xSI); \
emith_pop(xBP); \
emith_pop(xBX); \
emith_ret(); \
}
#else
#define PTR_SCALE 2
#define NA_TMP_REG xBX // non-arg tmp from reg_temp[]
#define EMIT_REX_FOR_PTR()
#define host_arg2reg(rd, arg) \
switch (arg) { \
case 0: rd = xAX; break; \
@ -612,7 +691,6 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
case 2: rd = xCX; break; \
}
/* SH2 drc specific */
#define emith_sh2_drc_entry() { \
emith_push(xBX); \
emith_push(xBP); \
@ -628,15 +706,33 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
emith_ret(); \
}
// assumes EBX is free temporary
#endif
#define emith_save_caller_regs(mask) do { \
if ((mask) & (1 << xAX)) emith_push(xAX); \
if ((mask) & (1 << xCX)) emith_push(xCX); \
if ((mask) & (1 << xDX)) emith_push(xDX); \
if ((mask) & (1 << xSI)) emith_push(xSI); \
if ((mask) & (1 << xDI)) emith_push(xDI); \
} while (0)
#define emith_restore_caller_regs(mask) do { \
if ((mask) & (1 << xDI)) emith_pop(xDI); \
if ((mask) & (1 << xSI)) emith_pop(xSI); \
if ((mask) & (1 << xDX)) emith_pop(xDX); \
if ((mask) & (1 << xCX)) emith_pop(xCX); \
if ((mask) & (1 << xAX)) emith_pop(xAX); \
} while (0)
#define emith_sh2_wcall(a, tab) { \
int arg2_; \
host_arg2reg(arg2_, 2); \
emith_lsr(xBX, a, SH2_WRITE_SHIFT); \
EMIT_OP_MODRM(0x8b, 0, xBX, 4); \
EMIT_SIB(2, xBX, tab); /* mov ebx, [tab + ebx * 4] */ \
emith_move_r_r(arg2_, CONTEXT_REG); \
emith_jump_reg(xBX); \
emith_lsr(NA_TMP_REG, a, SH2_WRITE_SHIFT); \
EMIT_REX_FOR_PTR(); \
EMIT_OP_MODRM(0x8b, 0, NA_TMP_REG, 4); \
EMIT_SIB(PTR_SCALE, NA_TMP_REG, tab); /* mov tmp, [tab + tmp * {4,8}] */ \
emith_move_r_r_ptr(arg2_, CONTEXT_REG); \
emith_jump_reg(NA_TMP_REG); \
}
#define emith_sh2_dtbf_loop() { \
@ -697,8 +793,8 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI };
JMP8_EMIT(ICOND_JE, jmp0); /* do_sub: */ \
emith_sub_r_r(rn, rm); \
JMP8_EMIT_NC(jmp1); /* done: */ \
emith_setc(tmp_); \
EMIT_OP_MODRM(0x31, 3, tmp_, sr); /* T = Q1 ^ Q2 */ \
emith_adc_r_r(tmp_, tmp_); \
emith_eor_r_r(sr, tmp_); \
rcache_free_tmp(tmp_); \
}

View File

@ -29,6 +29,7 @@
#include <assert.h>
#include "../../pico/pico_int.h"
#include "../../pico/arm_features.h"
#include "sh2.h"
#include "compiler.h"
#include "../drc/cmn.h"
@ -47,10 +48,11 @@
#define MAX_LOCAL_BRANCHES 32
// debug stuff
// 1 - warnings/errors
// 2 - block info/smc
// 4 - asm
// 8 - runtime block entry log
// 01 - warnings/errors
// 02 - block info/smc
// 04 - asm
// 08 - runtime block entry log
// 10 - smc self-check
// {
#ifndef DRC_DEBUG
#define DRC_DEBUG 0
@ -324,6 +326,27 @@ static temp_reg_t reg_temp[] = {
{ xDX, },
};
#elif defined(__x86_64__)
#include "../drc/emit_x86.c"
static const int reg_map_g2h[] = {
-1, -1, -1, -1,
-1, -1, -1, -1,
-1, -1, -1, -1,
-1, -1, -1, -1,
-1, -1, -1, xBX,
-1, -1, -1, -1,
};
// ax, cx, dx are usually temporaries by convention
static temp_reg_t reg_temp[] = {
{ xAX, },
{ xCX, },
{ xDX, },
{ xSI, },
{ xDI, },
};
#else
#error unsupported arch
#endif
@ -419,7 +442,7 @@ static void add_to_block_list(struct block_list **blist, struct block_desc *bloc
static void rm_from_block_list(struct block_list **blist, struct block_desc *block)
{
struct block_list *prev = NULL, *current = *blist;
for (; current != NULL; prev = current, current = current->next) {
for (; current != NULL; current = current->next) {
if (current->block == block) {
if (prev == NULL)
*blist = current->next;
@ -428,6 +451,7 @@ static void rm_from_block_list(struct block_list **blist, struct block_desc *blo
free(current);
return;
}
prev = current;
}
dbg(1, "can't rm block %p (%08x-%08x)",
block, block->addr, block->addr + block->size);
@ -514,6 +538,29 @@ missing:
dbg(1, "rm_from_hashlist: be %p %08x missing?", be, be->pc);
}
static void unregister_links(struct block_entry *be, int tcache_id)
{
struct block_link *bl_unresolved = unresolved_links[tcache_id];
struct block_link *bl, *bl_next;
for (bl = be->links; bl != NULL; ) {
bl_next = bl->next;
bl->next = bl_unresolved;
bl_unresolved = bl;
bl = bl_next;
}
be->links = NULL;
unresolved_links[tcache_id] = bl_unresolved;
}
// unlike sh2_smc_rm_block, the block stays and can still be accessed
// by other already directly linked blocks, just not preferred
static void kill_block_entry(struct block_entry *be, int tcache_id)
{
rm_from_hashlist(be, tcache_id);
unregister_links(be, tcache_id);
}
static struct block_desc *dr_add_block(u32 addr, u16 size_lit,
u16 size_nolit, int is_slave, int *blk_id)
{
@ -524,8 +571,10 @@ static struct block_desc *dr_add_block(u32 addr, u16 size_lit,
// do a lookup to get tcache_id and override check
be = dr_get_entry(addr, is_slave, &tcache_id);
if (be != NULL)
dbg(1, "block override for %08x", addr);
if (be != NULL) {
dbg(1, "block override for %08x, was %p", addr, be->tcache_ptr);
kill_block_entry(be, tcache_id);
}
bcount = &block_counts[tcache_id];
if (*bcount >= block_max_counts[tcache_id]) {
@ -891,13 +940,12 @@ do_alloc:
return tr->hreg;
}
static int rcache_get_arg_id(int arg)
static int rcache_get_hr_id(int hr)
{
int i, r = 0;
host_arg2reg(r, arg);
int i;
for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
if (reg_temp[i].hreg == r)
if (reg_temp[i].hreg == hr)
break;
if (i == ARRAY_SIZE(reg_temp)) // can't happen
@ -910,7 +958,7 @@ static int rcache_get_arg_id(int arg)
gconst_check_evict(reg_temp[i].greg);
}
else if (reg_temp[i].type == HR_TEMP) {
printf("arg %d reg %d already used, aborting\n", arg, r);
printf("host reg %d already used, aborting\n", hr);
exit(1);
}
@ -920,6 +968,13 @@ static int rcache_get_arg_id(int arg)
return i;
}
static int rcache_get_arg_id(int arg)
{
int r = 0;
host_arg2reg(r, arg);
return rcache_get_hr_id(r);
}
// get a reg to be used as function arg
static int rcache_get_tmp_arg(int arg)
{
@ -929,6 +984,15 @@ static int rcache_get_tmp_arg(int arg)
return reg_temp[id].hreg;
}
// ... as return value after a call
static int rcache_get_tmp_ret(void)
{
int id = rcache_get_hr_id(RET_REG);
reg_temp[id].type = HR_TEMP;
return reg_temp[id].hreg;
}
// same but caches a reg. RC_GR_READ only.
static int rcache_get_reg_arg(int arg, sh2_reg_e r)
{
@ -1076,8 +1140,8 @@ static int emit_get_rbase_and_offs(u32 a, u32 *offs)
// XXX: could use some related reg
hr = rcache_get_tmp();
emith_ctx_read(hr, poffs);
emith_add_r_imm(hr, a & mask & ~0xff);
emith_ctx_read_ptr(hr, poffs);
emith_add_r_r_ptr_imm(hr, hr, a & mask & ~0xff);
*offs = a & 0xff; // XXX: ARM oriented..
return hr;
}
@ -1126,7 +1190,7 @@ static int emit_memhandler_read_(int size, int ram_check)
emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
arg1 = rcache_get_tmp_arg(1);
emith_move_r_r(arg1, CONTEXT_REG);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
#if 0 // can't do this because of unmapped reads
// ndef PDB_NET
@ -1180,8 +1244,7 @@ static int emit_memhandler_read_(int size, int ram_check)
if (reg_map_g2h[SHR_SR] != -1)
emith_ctx_read(reg_map_g2h[SHR_SR], SHR_SR * 4);
// assuming arg0 and retval reg matches
return rcache_get_tmp_arg(0);
return rcache_get_tmp_ret();
}
static int emit_memhandler_read(int size)
@ -1251,7 +1314,7 @@ static void emit_memhandler_write(int size)
emith_call(sh2_drc_write16);
break;
case 2: // 32
emith_move_r_r(ctxr, CONTEXT_REG);
emith_move_r_r_ptr(ctxr, CONTEXT_REG);
emith_call(sh2_drc_write32);
break;
}
@ -1323,26 +1386,23 @@ static void emit_do_static_regs(int is_write, int tmpr)
}
}
/* just after lookup function, jump to address returned */
static void emit_block_entry(void)
{
int arg0;
host_arg2reg(arg0, 0);
#if (DRC_DEBUG & 8) || defined(PDB)
int arg1, arg2;
host_arg2reg(arg1, 1);
host_arg2reg(arg2, 2);
emit_do_static_regs(1, arg2);
emith_move_r_r(arg1, CONTEXT_REG);
emith_move_r_r_ptr(arg1, CONTEXT_REG);
emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
emith_call(sh2_drc_log_entry);
rcache_invalidate();
#endif
emith_tst_r_r(arg0, arg0);
emith_tst_r_r(RET_REG, RET_REG);
EMITH_SJMP_START(DCOND_EQ);
emith_jump_reg_c(DCOND_NE, arg0);
emith_jump_reg_c(DCOND_NE, RET_REG);
EMITH_SJMP_END(DCOND_EQ);
}
@ -1480,13 +1540,22 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
// make block entry
v = block->entry_count;
if (v < ARRAY_SIZE(block->entryp)) {
if (v < ARRAY_SIZE(block->entryp))
{
struct block_entry *be_old;
block->entryp[v].pc = pc;
block->entryp[v].tcache_ptr = tcache_ptr;
block->entryp[v].links = NULL;
#if (DRC_DEBUG & 2)
block->entryp[v].block = block;
#endif
be_old = dr_get_entry(pc, sh2->is_slave, &tcache_id);
if (be_old != NULL) {
dbg(1, "entry override for %08x, was %p", pc, be_old->tcache_ptr);
kill_block_entry(be_old, tcache_id);
}
add_to_hashlist(&block->entryp[v], tcache_id);
block->entry_count++;
@ -1514,6 +1583,22 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
emit_move_r_imm32(SHR_PC, pc);
rcache_clean();
#if (DRC_DEBUG & 0x10)
rcache_get_reg_arg(0, SHR_PC);
tmp = emit_memhandler_read(2);
tmp2 = rcache_get_tmp();
tmp3 = rcache_get_tmp();
emith_move_r_imm(tmp2, FETCH32(pc));
emith_move_r_imm(tmp3, 0);
emith_cmp_r_r(tmp, tmp2);
EMITH_SJMP_START(DCOND_EQ);
emith_read_r_r_offs_c(DCOND_NE, tmp3, tmp3, 0); // crash
EMITH_SJMP_END(DCOND_EQ);
rcache_free_tmp(tmp);
rcache_free_tmp(tmp2);
rcache_free_tmp(tmp3);
#endif
// check cycles
sr = rcache_get_reg(SHR_SR, RC_GR_READ);
emith_cmp_r_imm(sr, 0);
@ -2650,14 +2735,18 @@ end_op:
struct op_data *opd_b =
(op_flags[i] & OF_DELAY_OP) ? &ops[i-1] : opd;
u32 target_pc = opd_b->imm;
int cond = -1;
int cond = -1, ncond = -1;
void *target = NULL;
EMITH_SJMP_DECL_();
sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
FLUSH_CYCLES(sr);
rcache_clean();
if (opd_b->op != OP_BRANCH)
if (opd_b->op != OP_BRANCH) {
cond = (opd_b->op == OP_BRANCH_CF) ? DCOND_EQ : DCOND_NE;
ncond = (opd_b->op == OP_BRANCH_CF) ? DCOND_NE : DCOND_EQ;
}
if (cond != -1) {
int ctaken = (op_flags[i] & OF_DELAY_OP) ? 1 : 2;
@ -2666,9 +2755,9 @@ end_op:
else
emith_tst_r_imm(sr, T);
EMITH_SJMP_START_(ncond);
emith_sub_r_imm_c(cond, sr, ctaken<<12);
}
rcache_clean();
#if LINK_BRANCHES
if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0)
@ -2697,8 +2786,10 @@ end_op:
return NULL;
}
if (cond != -1)
if (cond != -1) {
emith_jump_cond_patchable(cond, target);
EMITH_SJMP_END_(ncond);
}
else {
emith_jump_patchable(target);
rcache_invalidate();
@ -2853,18 +2944,18 @@ static void sh2_generate_utils(void)
rcache_invalidate();
emith_ctx_read(arg0, SHR_PC * 4);
emith_ctx_read(arg1, offsetof(SH2, is_slave));
emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
emith_add_r_r_ptr_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
emith_call(dr_lookup_block);
emit_block_entry();
// lookup failed, call sh2_translate()
emith_move_r_r(arg0, CONTEXT_REG);
emith_move_r_r_ptr(arg0, CONTEXT_REG);
emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
emith_call(sh2_translate);
emit_block_entry();
// sh2_translate() failed, flush cache and retry
emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
emith_call(flush_tcache);
emith_move_r_r(arg0, CONTEXT_REG);
emith_move_r_r_ptr(arg0, CONTEXT_REG);
emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
emith_call(sh2_translate);
emit_block_entry();
@ -2891,13 +2982,13 @@ static void sh2_generate_utils(void)
emith_add_r_imm(tmp, 4);
tmp = rcache_get_reg_arg(1, SHR_SR);
emith_clear_msb(tmp, tmp, 22);
emith_move_r_r(arg2, CONTEXT_REG);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
rcache_invalidate();
// push PC
rcache_get_reg_arg(0, SHR_SP);
emith_ctx_read(arg1, SHR_PC * 4);
emith_move_r_r(arg2, CONTEXT_REG);
emith_move_r_r_ptr(arg2, CONTEXT_REG);
emith_call(p32x_sh2_write32);
rcache_invalidate();
// update I, cycles, do callback
@ -2907,16 +2998,16 @@ static void sh2_generate_utils(void)
emith_or_r_r_lsl(sr, arg1, I_SHIFT);
emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
rcache_flush();
emith_move_r_r(arg0, CONTEXT_REG);
emith_move_r_r_ptr(arg0, CONTEXT_REG);
emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
// obtain new PC
emith_lsl(arg0, arg0, 2);
emith_lsl(arg0, RET_REG, 2);
emith_ctx_read(arg1, SHR_VBR * 4);
emith_add_r_r(arg0, arg1);
emit_memhandler_read(2);
emith_ctx_write(arg0, SHR_PC * 4);
#ifdef __i386__
emith_add_r_imm(xSP, 4); // fix stack
tmp = emit_memhandler_read(2);
emith_ctx_write(tmp, SHR_PC * 4);
#if defined(__i386__) || defined(__x86_64__)
emith_add_r_r_ptr_imm(xSP, xSP, sizeof(void *)); // fix stack
#endif
emith_jump(sh2_drc_dispatcher);
rcache_invalidate();
@ -2924,19 +3015,19 @@ static void sh2_generate_utils(void)
// sh2_drc_entry(SH2 *sh2)
sh2_drc_entry = (void *)tcache_ptr;
emith_sh2_drc_entry();
emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
emith_move_r_r_ptr(CONTEXT_REG, arg0); // move ctx, arg0
emit_do_static_regs(0, arg2);
emith_call(sh2_drc_test_irq);
emith_jump(sh2_drc_dispatcher);
// sh2_drc_write8(u32 a, u32 d)
sh2_drc_write8 = (void *)tcache_ptr;
emith_ctx_read(arg2, offsetof(SH2, write8_tab));
emith_ctx_read_ptr(arg2, offsetof(SH2, write8_tab));
emith_sh2_wcall(arg0, arg2);
// sh2_drc_write16(u32 a, u32 d)
sh2_drc_write16 = (void *)tcache_ptr;
emith_ctx_read(arg2, offsetof(SH2, write16_tab));
emith_ctx_read_ptr(arg2, offsetof(SH2, write16_tab));
emith_sh2_wcall(arg0, arg2);
#ifdef PDB_NET
@ -2962,7 +3053,7 @@ static void sh2_generate_utils(void)
emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
emith_adc_r_imm(arg2, 0x01000000); \
emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
emith_move_r_r(arg2, CONTEXT_REG); \
emith_move_r_r_ptr(arg2, CONTEXT_REG); \
emith_jump(func); \
func = tmp; \
}
@ -2992,13 +3083,12 @@ static void sh2_generate_utils(void)
#endif
}
static void sh2_smc_rm_block_entry(struct block_desc *bd, int tcache_id, u32 ram_mask)
static void sh2_smc_rm_block(struct block_desc *bd, int tcache_id, u32 ram_mask)
{
struct block_link *bl, *bl_next, *bl_unresolved;
u32 i, addr, end_addr;
void *tmp;
dbg(2, " killing entry %08x-%08x-%08x, blkid %d,%d",
dbg(2, " killing block %08x-%08x-%08x, blkid %d,%d",
bd->addr, bd->addr + bd->size_nolit, bd->addr + bd->size,
tcache_id, bd - block_tables[tcache_id]);
if (bd->addr == 0 || bd->entry_count == 0) {
@ -3015,7 +3105,6 @@ static void sh2_smc_rm_block_entry(struct block_desc *bd, int tcache_id, u32 ram
}
tmp = tcache_ptr;
bl_unresolved = unresolved_links[tcache_id];
// remove from hash table, make incoming links unresolved
// XXX: maybe patch branches w/flush instead?
@ -3031,42 +3120,49 @@ static void sh2_smc_rm_block_entry(struct block_desc *bd, int tcache_id, u32 ram
host_instructions_updated(bd->entryp[i].tcache_ptr, tcache_ptr);
for (bl = bd->entryp[i].links; bl != NULL; ) {
bl_next = bl->next;
bl->next = bl_unresolved;
bl_unresolved = bl;
bl = bl_next;
}
unregister_links(&bd->entryp[i], tcache_id);
}
tcache_ptr = tmp;
unresolved_links[tcache_id] = bl_unresolved;
bd->addr = bd->size = bd->size_nolit = 0;
bd->entry_count = 0;
}
static void sh2_smc_rm_block(u32 a, u16 *drc_ram_blk, int tcache_id, u32 shift, u32 mask)
/*
04205:243: == msh2 block #0,200 060017a8-060017f0 -> 0x27cb9c
060017a8 d11c MOV.L @($70,PC),R1 ; @$0600181c
04230:261: msh2 xsh w32 [260017a8] d225e304
04230:261: msh2 smc check @260017a8
04239:226: = ssh2 enter 060017a8 0x27cb9c, c=173
*/
static void sh2_smc_rm_blocks(u32 a, u16 *drc_ram_blk, int tcache_id, u32 shift, u32 mask)
{
struct block_list **blist = NULL, *entry;
u32 from = ~0, to = 0, end_addr, taddr, i;
struct block_desc *block;
u32 start_addr, end_addr, taddr, i;
u32 from = ~0, to = 0;
// ignore cache-through
a &= ~0x20000000;
blist = &inval_lookup[tcache_id][(a & mask) / INVAL_PAGE_SIZE];
entry = *blist;
while (entry != NULL) {
block = entry->block;
end_addr = block->addr + block->size;
if (block->addr <= a && a < end_addr) {
start_addr = block->addr & ~0x20000000;
end_addr = start_addr + block->size;
if (start_addr <= a && a < end_addr) {
// get addr range that includes all removed blocks
if (from > block->addr)
from = block->addr;
if (from > start_addr)
from = start_addr;
if (to < end_addr)
to = end_addr;
sh2_smc_rm_block_entry(block, tcache_id, mask);
if (a >= block->addr + block->size_nolit)
if (a >= start_addr + block->size_nolit)
literal_disabled_frames = 3;
sh2_smc_rm_block(block, tcache_id, mask);
// entry lost, restart search
entry = *blist;
@ -3088,12 +3184,13 @@ static void sh2_smc_rm_block(u32 a, u16 *drc_ram_blk, int tcache_id, u32 shift,
for (; entry != NULL; entry = entry->next) {
block = entry->block;
if (block->addr > a) {
if (to > block->addr)
to = block->addr;
start_addr = block->addr & ~0x20000000;
if (start_addr > a) {
if (to > start_addr)
to = start_addr;
}
else {
end_addr = block->addr + block->size;
end_addr = start_addr + block->size;
if (from < end_addr)
from = end_addr;
}
@ -3110,13 +3207,13 @@ static void sh2_smc_rm_block(u32 a, u16 *drc_ram_blk, int tcache_id, u32 shift,
void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
{
dbg(2, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
sh2_smc_rm_block(a, Pico32xMem->drcblk_ram, 0, SH2_DRCBLK_RAM_SHIFT, 0x3ffff);
sh2_smc_rm_blocks(a, Pico32xMem->drcblk_ram, 0, SH2_DRCBLK_RAM_SHIFT, 0x3ffff);
}
void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
{
dbg(2, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
sh2_smc_rm_block(a, Pico32xMem->drcblk_da[cpuid],
sh2_smc_rm_blocks(a, Pico32xMem->drcblk_da[cpuid],
1 + cpuid, SH2_DRCBLK_DA_SHIFT, 0xfff);
}

View File

@ -610,6 +610,7 @@ unsigned DasmSH2(char *buffer, unsigned pc, UINT16 opcode)
case 14: flags = op1110(buffer,pc,opcode); break;
default: flags = op1111(buffer,pc,opcode); break;
}
(void)flags;
return 0;//2 | flags | DASMFLAG_SUPPORTED;
}

View File

@ -237,7 +237,7 @@ static void dump_regs(SH2 *sh2)
printf("%csh2 SR: %03x PR: %08x\n", csh2, sh2->sr, sh2->pr);
}
void do_sh2_cmp(SH2 *current)
void REGPARM(1) do_sh2_cmp(SH2 *current)
{
static int current_slave;
static u32 current_val;
@ -251,6 +251,13 @@ void do_sh2_cmp(SH2 *current)
int cycles;
int i, ret;
#if 0
sr = current->sr;
current->sr &= 0x3f3;
do_sh2_trace(current, (signed int)sr >> 12);
current->sr = sr;
return;
#endif
sh2ref[1].is_slave = 1;
while (1) {

View File

@ -118,7 +118,7 @@ void REGPARM(3) p32x_sh2_write32(unsigned int a, unsigned int d, SH2 *sh2);
// debug
#ifdef DRC_CMP
void do_sh2_trace(SH2 *current, int cycles);
void do_sh2_cmp(SH2 *current);
void REGPARM(1) do_sh2_cmp(SH2 *current);
#endif
#endif /* __SH2_H__ */

View File

@ -422,6 +422,9 @@ void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
}
}
#define STEP_LS 24
#define STEP_N 440
#define sync_sh2s_normal p32x_sync_sh2s
//#define sync_sh2s_lockstep p32x_sync_sh2s
@ -451,6 +454,8 @@ void sync_sh2s_normal(unsigned int m68k_target)
target = m68k_target;
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (CYCLES_GT(target, now + STEP_N))
target = now + STEP_N;
while (CYCLES_GT(target, now))
{
@ -502,9 +507,10 @@ void sync_sh2s_normal(unsigned int m68k_target)
if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
ssh2.m68krcycles_done = m68k_target;
}
}
#define STEP_68K 24
// everyone is in sync now
Pico32x.comm_dirty = 0;
}
void sync_sh2s_lockstep(unsigned int m68k_target)
{
@ -515,7 +521,7 @@ void sync_sh2s_lockstep(unsigned int m68k_target)
mcycles = ssh2.m68krcycles_done;
while (mcycles < m68k_target) {
mcycles += STEP_68K;
mcycles += STEP_LS;
sync_sh2s_normal(mcycles);
}
}

View File

@ -191,12 +191,10 @@ static u32 p32x_reg_read16(u32 a)
int comreg = 1 << (a & 0x0f) / 2;
if (cycles - msh2.m68krcycles_done > 244
|| (Pico32x.comm_dirty_68k & comreg))
|| (Pico32x.comm_dirty & comreg))
p32x_sync_sh2s(cycles);
if (Pico32x.comm_dirty_sh2 & comreg)
Pico32x.comm_dirty_sh2 &= ~comreg;
else if (m68k_poll_detect(a, cycles, P32XF_68KCPOLL)) {
if (m68k_poll_detect(a, cycles, P32XF_68KCPOLL)) {
SekSetStop(1);
SekEndRun(16);
}
@ -388,14 +386,13 @@ static void p32x_reg_write8(u32 a, u32 d)
if (REG8IN16(r, a) == d)
return;
comreg = 1 << (a & 0x0f) / 2;
if (Pico32x.comm_dirty_68k & comreg)
p32x_sync_sh2s(cycles);
p32x_sync_sh2s(cycles);
REG8IN16(r, a) = d;
p32x_sh2_poll_event(&sh2s[0], SH2_STATE_CPOLL, cycles);
p32x_sh2_poll_event(&sh2s[1], SH2_STATE_CPOLL, cycles);
Pico32x.comm_dirty_68k |= comreg;
comreg = 1 << (a & 0x0f) / 2;
Pico32x.comm_dirty |= comreg;
if (cycles - (int)msh2.m68krcycles_done > 120)
p32x_sync_sh2s(cycles);
@ -451,20 +448,13 @@ static void p32x_reg_write16(u32 a, u32 d)
int cycles = SekCyclesDone();
int comreg;
if (r[a / 2] == d)
return;
comreg = 1 << (a & 0x0f) / 2;
if (Pico32x.comm_dirty_68k & comreg)
p32x_sync_sh2s(cycles);
p32x_sync_sh2s(cycles);
r[a / 2] = d;
p32x_sh2_poll_event(&sh2s[0], SH2_STATE_CPOLL, cycles);
p32x_sh2_poll_event(&sh2s[1], SH2_STATE_CPOLL, cycles);
Pico32x.comm_dirty_68k |= comreg;
if (cycles - (int)msh2.m68krcycles_done > 120)
p32x_sync_sh2s(cycles);
comreg = 1 << (a & 0x0f) / 2;
Pico32x.comm_dirty |= comreg;
return;
}
// PWM
@ -601,11 +591,7 @@ static u32 p32x_sh2reg_read16(u32 a, SH2 *sh2)
// comm port
if ((a & 0x30) == 0x20) {
int comreg = 1 << (a & 0x0f) / 2;
if (Pico32x.comm_dirty_68k & comreg)
Pico32x.comm_dirty_68k &= ~comreg;
else
sh2_poll_detect(sh2, a, SH2_STATE_CPOLL, 3);
sh2_poll_detect(sh2, a, SH2_STATE_CPOLL, 3);
sh2s_sync_on_read(sh2);
return r[a / 2];
}
@ -708,7 +694,7 @@ static void p32x_sh2reg_write8(u32 a, u32 d, SH2 *sh2)
p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL,
sh2_cycles_done_m68k(sh2));
comreg = 1 << (a & 0x0f) / 2;
Pico32x.comm_dirty_sh2 |= comreg;
Pico32x.comm_dirty |= comreg;
return;
}
@ -733,7 +719,7 @@ static void p32x_sh2reg_write16(u32 a, u32 d, SH2 *sh2)
p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL,
sh2_cycles_done_m68k(sh2));
comreg = 1 << (a & 0x0f) / 2;
Pico32x.comm_dirty_sh2 |= comreg;
Pico32x.comm_dirty |= comreg;
return;
}
// PWM
@ -1658,23 +1644,37 @@ static void get_bios(void)
Byteswap(Pico32xMem->m68k_rom, p32x_bios_g, sizeof(Pico32xMem->m68k_rom));
}
else {
static const u16 andb[] = { 0x0239, 0x00fe, 0x00a1, 0x5107 };
static const u16 p_d4[] = {
0x48e7, 0x8040, // movem.l d0/a1, -(sp)
0x227c, 0x00a1, 0x30f1, // movea.l #0xa130f1, a1
0x7007, // moveq.l #7, d0
0x12d8, //0: move.b (a0)+, (a1)+
0x5289, // addq.l #1, a1
0x51c8, 0xfffa, // dbra d0, 0b
0x0239, 0x00fe, 0x00a1, // and.b #0xfe, (0xa15107).l
0x5107,
0x4cdf, 0x0201 // movem.l (sp)+, d0/a1
};
// generate 68k ROM
ps = (u16 *)Pico32xMem->m68k_rom;
pl = (u32 *)ps;
for (i = 1; i < 0xc0/4; i++)
pl[i] = HWSWAP(0x880200 + (i - 1) * 6);
pl[0x70/4] = 0;
// fill with nops
for (i = 0xc0/2; i < 0x100/2; i++)
ps[i] = 0x4e71;
#if 0
ps[0xc0/2] = 0x46fc;
ps[0xc2/2] = 0x2700; // move #0x2700,sr
ps[0xfe/2] = 0x60fe; // jump to self
#else
// c0: don't need to care about RV - not emulated
ps[0xc8/2] = 0x1280; // move.b d0, (a1)
memcpy(ps + 0xca/2, andb, sizeof(andb)); // and.b #0xfe, (a15107)
ps[0xd2/2] = 0x4e75; // rts
// d4:
memcpy(ps + 0xd4/2, p_d4, sizeof(p_d4));
ps[0xfe/2] = 0x4e75; // rts
#endif
}
// fill remaining m68k_rom page with game ROM
memcpy(Pico32xMem->m68k_rom_bank + sizeof(Pico32xMem->m68k_rom),

View File

@ -391,8 +391,8 @@ int pm_seek(pm_file *stream, long offset, int whence)
offset = pos;
}
if (PicoMessage != NULL && offset > 4 * 1024 * 1024)
PicoMessage("Decompressing data...");
if (PicoIn.osdMessage != NULL && offset > 4 * 1024 * 1024)
PicoIn.osdMessage("Decompressing data...");
while (offset > 0) {
char buf[16 * 1024];

View File

@ -1297,8 +1297,8 @@ void cdd_process(void)
set_reg16(0x3e, 0x0000);
set_reg16(0x40, 0x000f);
if (PicoMCDcloseTray)
PicoMCDcloseTray();
if (PicoIn.mcdTrayClose)
PicoIn.mcdTrayClose();
return;
}
@ -1316,8 +1316,8 @@ void cdd_process(void)
set_reg16(0x3e, 0x0000);
set_reg16(0x40, ~CD_OPEN & 0x0f);
if (PicoMCDopenTray)
PicoMCDopenTray();
if (PicoIn.mcdTrayOpen)
PicoIn.mcdTrayOpen();
return;
}

View File

@ -15,9 +15,6 @@ static unsigned int mcd_m68k_cycle_mult;
static unsigned int mcd_m68k_cycle_base;
static unsigned int mcd_s68k_cycle_base;
void (*PicoMCDopenTray)(void) = NULL;
void (*PicoMCDcloseTray)(void) = NULL;
PICO_INTERNAL void PicoInitMCD(void)
{

View File

@ -387,14 +387,14 @@ void PDebugZ80Frame(void)
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
PicoSyncZ80(Pico.t.m68c_cnt + line_sample * 488);
if (PsndOut)
if (PicoIn.sndOut)
PsndGetSamples(line_sample);
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
PicoSyncZ80(Pico.t.m68c_cnt + 224 * 488);
z80_int();
}
if (PsndOut)
if (PicoIn.sndOut)
PsndGetSamples(224);
// sync z80
@ -402,7 +402,7 @@ void PDebugZ80Frame(void)
Pico.t.m68c_cnt += Pico.m.pal ? 151809 : 127671; // cycles adjusted for converter
PicoSyncZ80(Pico.t.m68c_cnt);
}
if (PsndOut && ym2612.dacen && PsndDacLine < lines)
if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
PsndDoDAC(lines - 1);
PsndDoPSG(lines - 1);

View File

@ -389,7 +389,7 @@ static int get_scanline(int is_from_z80);
static void psg_write_68k(u32 d)
{
// look for volume write and update if needed
if ((d & 0x90) == 0x90 && PsndPsgLine < Pico.m.scanline)
if ((d & 0x90) == 0x90 && Pico.snd.psg_line < Pico.m.scanline)
PsndDoPSG(Pico.m.scanline);
SN76496Write(d);
@ -399,7 +399,7 @@ static void psg_write_z80(u32 d)
{
if ((d & 0x90) == 0x90) {
int scanline = get_scanline(1);
if (PsndPsgLine < scanline)
if (Pico.snd.psg_line < scanline)
PsndDoPSG(scanline);
}
@ -895,41 +895,41 @@ void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new)
int xcycles = z80_cycles << 8;
/* check for overflows */
if ((mode_old & 4) && xcycles > timer_a_next_oflow)
if ((mode_old & 4) && xcycles > Pico.t.timer_a_next_oflow)
ym2612.OPN.ST.status |= 1;
if ((mode_old & 8) && xcycles > timer_b_next_oflow)
if ((mode_old & 8) && xcycles > Pico.t.timer_b_next_oflow)
ym2612.OPN.ST.status |= 2;
/* update timer a */
if (mode_old & 1)
while (xcycles > timer_a_next_oflow)
timer_a_next_oflow += timer_a_step;
while (xcycles > Pico.t.timer_a_next_oflow)
Pico.t.timer_a_next_oflow += Pico.t.timer_a_step;
if ((mode_old ^ mode_new) & 1) // turning on/off
{
if (mode_old & 1)
timer_a_next_oflow = TIMER_NO_OFLOW;
Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;
else
timer_a_next_oflow = xcycles + timer_a_step;
Pico.t.timer_a_next_oflow = xcycles + Pico.t.timer_a_step;
}
if (mode_new & 1)
elprintf(EL_YMTIMER, "timer a upd to %i @ %i", timer_a_next_oflow>>8, z80_cycles);
elprintf(EL_YMTIMER, "timer a upd to %i @ %i", Pico.t.timer_a_next_oflow>>8, z80_cycles);
/* update timer b */
if (mode_old & 2)
while (xcycles > timer_b_next_oflow)
timer_b_next_oflow += timer_b_step;
while (xcycles > Pico.t.timer_b_next_oflow)
Pico.t.timer_b_next_oflow += Pico.t.timer_b_step;
if ((mode_old ^ mode_new) & 2)
{
if (mode_old & 2)
timer_b_next_oflow = TIMER_NO_OFLOW;
Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;
else
timer_b_next_oflow = xcycles + timer_b_step;
Pico.t.timer_b_next_oflow = xcycles + Pico.t.timer_b_step;
}
if (mode_new & 2)
elprintf(EL_YMTIMER, "timer b upd to %i @ %i", timer_b_next_oflow>>8, z80_cycles);
elprintf(EL_YMTIMER, "timer b upd to %i @ %i", Pico.t.timer_b_next_oflow>>8, z80_cycles);
}
// ym2612 DAC and timer I/O handlers for z80
@ -941,7 +941,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
if (a == 1 && ym2612.OPN.ST.address == 0x2a) /* DAC data */
{
int scanline = get_scanline(is_from_z80);
//elprintf(EL_STATUS, "%03i -> %03i dac w %08x z80 %i", PsndDacLine, scanline, d, is_from_z80);
//elprintf(EL_STATUS, "%03i -> %03i dac w %08x z80 %i", Pico.snd.dac_line, scanline, d, is_from_z80);
ym2612.dacout = ((int)d - 0x80) << 6;
if (ym2612.dacen)
PsndDoDAC(scanline);
@ -977,13 +977,13 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
ym2612.OPN.ST.TA = TAnew;
//ym2612.OPN.ST.TAC = (1024-TAnew)*18;
//ym2612.OPN.ST.TAT = 0;
timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew);
Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew);
if (ym2612.OPN.ST.mode & 1) {
// this is not right, should really be done on overflow only
int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();
timer_a_next_oflow = (cycles << 8) + timer_a_step;
Pico.t.timer_a_next_oflow = (cycles << 8) + Pico.t.timer_a_step;
}
elprintf(EL_YMTIMER, "timer a set to %i, %i", 1024 - TAnew, timer_a_next_oflow>>8);
elprintf(EL_YMTIMER, "timer a set to %i, %i", 1024 - TAnew, Pico.t.timer_a_next_oflow>>8);
}
return 0;
}
@ -993,12 +993,12 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
ym2612.OPN.ST.TB = d;
//ym2612.OPN.ST.TBC = (256-d) * 288;
//ym2612.OPN.ST.TBT = 0;
timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d); // 262800
Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d); // 262800
if (ym2612.OPN.ST.mode & 2) {
int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();
timer_b_next_oflow = (cycles << 8) + timer_b_step;
Pico.t.timer_b_next_oflow = (cycles << 8) + Pico.t.timer_b_step;
}
elprintf(EL_YMTIMER, "timer b set to %i, %i", 256 - d, timer_b_next_oflow>>8);
elprintf(EL_YMTIMER, "timer b set to %i, %i", 256 - d, Pico.t.timer_b_next_oflow>>8);
}
return 0;
case 0x27: { /* mode, timer control */
@ -1029,7 +1029,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
int scanline = get_scanline(is_from_z80);
if (ym2612.dacen != (d & 0x80)) {
ym2612.dacen = d & 0x80;
PsndDacLine = scanline;
Pico.snd.dac_line = scanline;
}
#ifdef __GP2X__
if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, scanline);
@ -1065,9 +1065,9 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
#define ym2612_read_local() \
if (xcycles >= timer_a_next_oflow) \
if (xcycles >= Pico.t.timer_a_next_oflow) \
ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 1; \
if (xcycles >= timer_b_next_oflow) \
if (xcycles >= Pico.t.timer_b_next_oflow) \
ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 2
static u32 ym2612_read_local_z80(void)
@ -1076,8 +1076,9 @@ static u32 ym2612_read_local_z80(void)
ym2612_read_local();
elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i", ym2612.OPN.ST.status,
timer_a_next_oflow>>8, timer_b_next_oflow>>8, xcycles >> 8, (xcycles >> 8) / 228);
elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
return ym2612.OPN.ST.status;
}
@ -1087,8 +1088,9 @@ static u32 ym2612_read_local_68k(void)
ym2612_read_local();
elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i", ym2612.OPN.ST.status,
timer_a_next_oflow>>8, timer_b_next_oflow>>8, xcycles >> 8, (xcycles >> 8) / 228);
elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i",
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,
Pico.t.timer_b_next_oflow >> 8, xcycles >> 8, (xcycles >> 8) / 228);
return ym2612.OPN.ST.status;
}
@ -1098,10 +1100,12 @@ void ym2612_pack_state(void)
int tac, tat = 0, tbc, tbt = 0;
tac = 1024 - ym2612.OPN.ST.TA;
tbc = 256 - ym2612.OPN.ST.TB;
if (timer_a_next_oflow != TIMER_NO_OFLOW)
tat = (int)((double)(timer_a_step - timer_a_next_oflow) / (double)timer_a_step * tac * 65536);
if (timer_b_next_oflow != TIMER_NO_OFLOW)
tbt = (int)((double)(timer_b_step - timer_b_next_oflow) / (double)timer_b_step * tbc * 65536);
if (Pico.t.timer_a_next_oflow != TIMER_NO_OFLOW)
tat = (int)((double)(Pico.t.timer_a_step - Pico.t.timer_a_next_oflow)
/ (double)Pico.t.timer_a_step * tac * 65536);
if (Pico.t.timer_b_next_oflow != TIMER_NO_OFLOW)
tbt = (int)((double)(Pico.t.timer_b_step - Pico.t.timer_b_next_oflow)
/ (double)Pico.t.timer_b_step * tbc * 65536);
elprintf(EL_YMTIMER, "save: timer a %i/%i", tat >> 16, tac);
elprintf(EL_YMTIMER, "save: timer b %i/%i", tbt >> 16, tbc);
@ -1154,15 +1158,15 @@ void ym2612_unpack_state(void)
tac = (1024 - ym2612.OPN.ST.TA) << 16;
tbc = (256 - ym2612.OPN.ST.TB) << 16;
if (ym2612.OPN.ST.mode & 1)
timer_a_next_oflow = (int)((double)(tac - tat) / (double)tac * timer_a_step);
Pico.t.timer_a_next_oflow = (int)((double)(tac - tat) / (double)tac * Pico.t.timer_a_step);
else
timer_a_next_oflow = TIMER_NO_OFLOW;
Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;
if (ym2612.OPN.ST.mode & 2)
timer_b_next_oflow = (int)((double)(tbc - tbt) / (double)tbc * timer_b_step);
Pico.t.timer_b_next_oflow = (int)((double)(tbc - tbt) / (double)tbc * Pico.t.timer_b_step);
else
timer_b_next_oflow = TIMER_NO_OFLOW;
elprintf(EL_YMTIMER, "load: %i/%i, timer_a_next_oflow %i", tat>>16, tac>>16, timer_a_next_oflow >> 8);
elprintf(EL_YMTIMER, "load: %i/%i, timer_b_next_oflow %i", tbt>>16, tbc>>16, timer_b_next_oflow >> 8);
Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;
elprintf(EL_YMTIMER, "load: %i/%i, timer_a_next_oflow %i", tat>>16, tac>>16, Pico.t.timer_a_next_oflow >> 8);
elprintf(EL_YMTIMER, "load: %i/%i, timer_b_next_oflow %i", tbt>>16, tbc>>16, Pico.t.timer_b_next_oflow >> 8);
}
#if defined(NO_32X) && defined(_ASM_MEMORY_C)

View File

@ -14,7 +14,6 @@ struct Pico Pico;
struct PicoMem PicoMem;
PicoInterface PicoIn;
void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware
void (*PicoResetHook)(void) = NULL;
void (*PicoLineHook)(void) = NULL;
@ -344,6 +343,4 @@ void PicoGetInternal(pint_t which, pint_ret_t *r)
}
}
// callback to output message from emu
void (*PicoMessage)(const char *msg)=NULL;
// vim:ts=2:sw=2:expandtab

View File

@ -97,6 +97,15 @@ typedef struct
unsigned short quirks; // game-specific quirks: PQUIRK_*
unsigned short overclockM68k; // overclock the emulated 68k, in %
int sndRate; // rate in Hz
short *sndOut; // PCM output buffer
void (*writeSound)(int len); // write .sndOut callback, called once per frame
void (*osdMessage)(const char *msg); // output OSD message from emu, optional
void (*mcdTrayOpen)(void);
void (*mcdTrayClose)(void);
} PicoInterface;
extern PicoInterface PicoIn;
@ -108,18 +117,12 @@ int PicoReset(void);
void PicoLoopPrepare(void);
void PicoFrame(void);
void PicoFrameDrawOnly(void);
extern void (*PicoWriteSound)(int bytes); // called once per frame at the best time to send sound buffer (PsndOut) to hardware
extern void (*PicoMessage)(const char *msg); // callback to output text message from emu
typedef enum { PI_ROM, PI_ISPAL, PI_IS40_CELL, PI_IS240_LINES } pint_t;
typedef union { int vint; void *vptr; } pint_ret_t;
void PicoGetInternal(pint_t which, pint_ret_t *ret);
struct PicoEState;
// cd/mcd.c
extern void (*PicoMCDopenTray)(void);
extern void (*PicoMCDcloseTray)(void);
// pico.c
#define XPCM_BUFFER_SIZE (320+160)
typedef struct
@ -230,8 +233,6 @@ void Pico32xSetClocks(int msh2_hz, int ssh2_hz);
#define PICO_SSH2_HZ ((int)(7670442.0 * 2.4))
// sound.c
extern int PsndRate,PsndLen;
extern short *PsndOut;
extern void (*PsndMix_32_to_16l)(short *dest, int *src, int count);
void PsndRerate(int preserve_state);

View File

@ -50,7 +50,7 @@ PICO_INTERNAL void PicoPicoPCMReset(void)
PICO_INTERNAL void PicoPicoPCMRerate(int xpcm_rate)
{
stepsamples = (PsndRate<<10)/xpcm_rate;
stepsamples = (PicoIn.sndRate<<10)/xpcm_rate;
}
#define XSHIFT 6

View File

@ -153,7 +153,7 @@ static int PicoFrameHints(void)
}
// get samples from sound chips
if ((y == 224 || y == line_sample) && PsndOut)
if ((y == 224 || y == line_sample) && PicoIn.sndOut)
{
cycles = SekCyclesDone();
@ -241,7 +241,7 @@ static int PicoFrameHints(void)
#endif
// get samples from sound chips
if (y == 224 && PsndOut)
if (y == 224 && PicoIn.sndOut)
PsndGetSamples(y);
// Run scanline:
@ -324,9 +324,9 @@ static int PicoFrameHints(void)
cycles = SekCyclesDone();
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
PicoSyncZ80(cycles);
if (PsndOut && ym2612.dacen && PsndDacLine < lines)
if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
PsndDoDAC(lines - 1);
if (PsndOut && PsndPsgLine < lines)
if (PicoIn.sndOut && Pico.snd.psg_line < lines)
PsndDoPSG(lines - 1);
#ifdef PICO_CD

View File

@ -409,6 +409,19 @@ struct PicoTiming
unsigned int z80c_cnt; // z80 cycles done (this frame)
unsigned int z80c_aim;
int z80_scanline;
int timer_a_next_oflow, timer_a_step; // in z80 cycles
int timer_b_next_oflow, timer_b_step;
};
struct PicoSound
{
short len; // number of mono samples
short len_use; // adjusted
int len_e_add; // for non-int samples/frame
int len_e_cnt;
short dac_line;
short psg_line;
};
// run tools/mkoffsets pico/pico_int_o32.h if you change these
@ -419,6 +432,7 @@ struct Pico
struct PicoMisc m;
struct PicoTiming t;
struct PicoCartSave sv;
struct PicoSound snd;
struct PicoEState est;
struct PicoMS ms;
@ -568,8 +582,8 @@ struct Pico32x
unsigned int dmac0_fifo_ptr;
unsigned short vdp_fbcr_fake;
unsigned short pad2;
unsigned char comm_dirty_68k;
unsigned char comm_dirty_sh2;
unsigned char comm_dirty;
unsigned char pad3; // was comm_dirty_sh2
unsigned char pwm_irq_cnt;
unsigned char pad1;
unsigned short pwm_p[2]; // pwm pos in fifo
@ -781,10 +795,6 @@ void SekInterruptClearS68k(int irq);
// sound/sound.c
extern short cdda_out_buffer[2*1152];
extern int PsndLen_exc_cnt;
extern int PsndLen_exc_add;
extern int timer_a_next_oflow, timer_a_step; // in z80 cycles
extern int timer_b_next_oflow, timer_b_step;
void cdda_start_play(int lba_base, int lba_offset, int lb_len);
@ -799,16 +809,16 @@ void ym2612_unpack_state(void);
#define TIMER_B_TICK_ZCYCLES 262800 // 275251 broken, see Dai Makaimura
#define timers_cycle() \
if (timer_a_next_oflow > 0 && timer_a_next_oflow < TIMER_NO_OFLOW) \
timer_a_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256; \
if (timer_b_next_oflow > 0 && timer_b_next_oflow < TIMER_NO_OFLOW) \
timer_b_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256; \
if (Pico.t.timer_a_next_oflow > 0 && Pico.t.timer_a_next_oflow < TIMER_NO_OFLOW) \
Pico.t.timer_a_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256; \
if (Pico.t.timer_b_next_oflow > 0 && Pico.t.timer_b_next_oflow < TIMER_NO_OFLOW) \
Pico.t.timer_b_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256; \
ym2612_sync_timers(0, ym2612.OPN.ST.mode, ym2612.OPN.ST.mode);
#define timers_reset() \
timer_a_next_oflow = timer_b_next_oflow = TIMER_NO_OFLOW; \
timer_a_step = TIMER_A_TICK_ZCYCLES * 1024; \
timer_b_step = TIMER_B_TICK_ZCYCLES * 256;
Pico.t.timer_a_next_oflow = Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW; \
Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * 1024; \
Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * 256;
// videoport.c
@ -850,7 +860,6 @@ PICO_INTERNAL void PsndDoPSG(int line_to);
PICO_INTERNAL void PsndClear(void);
PICO_INTERNAL void PsndGetSamples(int y);
PICO_INTERNAL void PsndGetSamplesMS(void);
extern int PsndDacLine, PsndPsgLine;
// sms.c
#ifndef NO_SMS
@ -974,7 +983,7 @@ static __inline int isspace_(int c)
// emulation event logging
#ifndef EL_LOGMASK
# ifdef __x86_64__ // HACK
# define EL_LOGMASK (EL_STATUS|EL_IDLE|EL_ANOMALY)
# define EL_LOGMASK (EL_STATUS|EL_ANOMALY)
# else
# define EL_LOGMASK (EL_STATUS)
# endif

View File

@ -6,13 +6,13 @@
#define OFS_Pico_m_hardware 0x0047
#define OFS_Pico_m_z80_reset 0x004f
#define OFS_Pico_m_sram_reg 0x0049
#define OFS_Pico_sv 0x007c
#define OFS_Pico_sv_data 0x007c
#define OFS_Pico_sv_start 0x0080
#define OFS_Pico_sv_end 0x0084
#define OFS_Pico_sv_flags 0x0088
#define OFS_Pico_rom 0x031c
#define OFS_Pico_romsize 0x0320
#define OFS_Pico_sv 0x008c
#define OFS_Pico_sv_data 0x008c
#define OFS_Pico_sv_start 0x0090
#define OFS_Pico_sv_end 0x0094
#define OFS_Pico_sv_flags 0x0098
#define OFS_Pico_rom 0x033c
#define OFS_Pico_romsize 0x0340
#define OFS_EST_DrawScanline 0x00
#define OFS_EST_rendstatus 0x04
#define OFS_EST_DrawLineDest 0x08

View File

@ -8,10 +8,8 @@
/*
* TODO:
* - start in a state as if BIOS ran
* - remaining status flags (OVR/COL)
* - RAM support in mapper
* - region support
* - SN76496 DAC-like usage
* - H counter
*/
#include "pico_int.h"
@ -133,8 +131,9 @@ static void z80_sms_out(unsigned short a, unsigned char d)
case 0x40:
case 0x41:
if (PicoIn.opt & POPT_EN_PSG)
SN76496Write(d);
if ((d & 0x90) == 0x90 && Pico.snd.psg_line < Pico.m.scanline)
PsndDoPSG(Pico.m.scanline);
SN76496Write(d);
break;
case 0x80:
@ -300,12 +299,16 @@ void PicoFrameMS(void)
}
}
// 224 because of how it's done for MD...
if (y == 224 && PicoIn.sndOut)
PsndGetSamplesMS();
cycles_aim += cycles_line;
cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8;
}
if (PsndOut)
PsndGetSamplesMS();
if (PicoIn.sndOut && Pico.snd.psg_line < lines)
PsndDoPSG(lines - 1);
}
void PicoFrameDrawOnlyMS(void)
@ -319,3 +322,4 @@ void PicoFrameDrawOnlyMS(void)
PicoLineMode4(y);
}
// vim:ts=2:sw=2:expandtab

View File

@ -25,31 +25,20 @@ static unsigned short dac_info[312+4]; // pos in sample buffer
// cdda output buffer
short cdda_out_buffer[2*1152];
// for Pico
int PsndRate=0;
int PsndLen=0; // number of mono samples, multiply by 2 for stereo
int PsndLen_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60
int PsndLen_exc_cnt=0;
int PsndDacLine, PsndPsgLine;
short *PsndOut=NULL; // PCM data buffer
static int PsndLen_use;
// timers
int timer_a_next_oflow, timer_a_step; // in z80 cycles
int timer_b_next_oflow, timer_b_step;
// sn76496
extern int *sn76496_regs;
static void dac_recalculate(void)
{
int i, dac_cnt, pos, len, lines = Pico.m.pal ? 313 : 262, mid = Pico.m.pal ? 68 : 93;
int lines = Pico.m.pal ? 313 : 262;
int mid = Pico.m.pal ? 68 : 93;
int i, dac_cnt, pos, len;
if (PsndLen <= lines)
if (Pico.snd.len <= lines)
{
// shrinking algo
dac_cnt = -PsndLen;
dac_cnt = -Pico.snd.len;
len=1; pos=0;
dac_info[225] = 1;
@ -60,14 +49,14 @@ static void dac_recalculate(void)
pos++;
dac_cnt += lines;
}
dac_cnt -= PsndLen;
dac_cnt -= Pico.snd.len;
dac_info[i] = pos;
}
}
else
{
// stretching
dac_cnt = PsndLen;
dac_cnt = Pico.snd.len;
pos=0;
for(i = 225; i != 224; i++)
{
@ -78,11 +67,11 @@ static void dac_recalculate(void)
len++;
}
if (i == mid) // midpoint
while(pos+len < PsndLen/2) {
while(pos+len < Pico.snd.len/2) {
dac_cnt -= lines;
len++;
}
dac_cnt += PsndLen;
dac_cnt += Pico.snd.len;
pos += len;
dac_info[i] = pos;
}
@ -112,7 +101,7 @@ void PsndRerate(int preserve_state)
ym2612_pack_state();
memcpy(state, YM2612GetRegs(), 0x204);
}
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate);
if (preserve_state) {
// feed it back it's own registers, just like after loading state
memcpy(YM2612GetRegs(), state, 0x204);
@ -120,16 +109,16 @@ void PsndRerate(int preserve_state)
}
if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate);
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PicoIn.sndRate);
if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state
if (state)
free(state);
// calculate PsndLen
PsndLen=PsndRate / target_fps;
PsndLen_exc_add=((PsndRate - PsndLen*target_fps)<<16) / target_fps;
PsndLen_exc_cnt=0;
// calculate Pico.snd.len
Pico.snd.len = PicoIn.sndRate / target_fps;
Pico.snd.len_e_add = ((PicoIn.sndRate - Pico.snd.len * target_fps) << 16) / target_fps;
Pico.snd.len_e_cnt = 0;
// recalculate dac info
dac_recalculate();
@ -137,7 +126,7 @@ void PsndRerate(int preserve_state)
// clear all buffers
memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);
memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));
if (PsndOut)
if (PicoIn.sndOut)
PsndClear();
// set mixer
@ -150,24 +139,24 @@ void PsndRerate(int preserve_state)
PICO_INTERNAL void PsndStartFrame(void)
{
// compensate for float part of PsndLen
PsndLen_use = PsndLen;
PsndLen_exc_cnt += PsndLen_exc_add;
if (PsndLen_exc_cnt >= 0x10000) {
PsndLen_exc_cnt -= 0x10000;
PsndLen_use++;
// compensate for float part of Pico.snd.len
Pico.snd.len_use = Pico.snd.len;
Pico.snd.len_e_cnt += Pico.snd.len_e_add;
if (Pico.snd.len_e_cnt >= 0x10000) {
Pico.snd.len_e_cnt -= 0x10000;
Pico.snd.len_use++;
}
PsndDacLine = PsndPsgLine = 0;
Pico.snd.dac_line = Pico.snd.psg_line = 0;
Pico.m.status &= ~1;
dac_info[224] = PsndLen_use;
dac_info[224] = Pico.snd.len_use;
}
PICO_INTERNAL void PsndDoDAC(int line_to)
{
int pos, pos1, len;
int dout = ym2612.dacout;
int line_from = PsndDacLine;
int line_from = Pico.snd.dac_line;
if (line_to >= 313)
line_to = 312;
@ -178,23 +167,23 @@ PICO_INTERNAL void PsndDoDAC(int line_to)
if (len <= 0)
return;
PsndDacLine = line_to + 1;
Pico.snd.dac_line = line_to + 1;
if (!PsndOut)
if (!PicoIn.sndOut)
return;
if (PicoIn.opt & POPT_EN_STEREO) {
short *d = PsndOut + pos*2;
short *d = PicoIn.sndOut + pos*2;
for (; len > 0; len--, d+=2) *d += dout;
} else {
short *d = PsndOut + pos;
short *d = PicoIn.sndOut + pos;
for (; len > 0; len--, d++) *d += dout;
}
}
PICO_INTERNAL void PsndDoPSG(int line_to)
{
int line_from = PsndPsgLine;
int line_from = Pico.snd.psg_line;
int pos, pos1, len;
int stereo = 0;
@ -209,16 +198,16 @@ PICO_INTERNAL void PsndDoPSG(int line_to)
if (len <= 0)
return;
PsndPsgLine = line_to + 1;
Pico.snd.psg_line = line_to + 1;
if (!PsndOut || !(PicoIn.opt & POPT_EN_PSG))
if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_PSG))
return;
if (PicoIn.opt & POPT_EN_STEREO) {
stereo = 1;
pos <<= 1;
}
SN76496Update(PsndOut + pos, len, stereo);
SN76496Update(PicoIn.sndOut + pos, len, stereo);
}
// cdda
@ -227,8 +216,8 @@ static void cdda_raw_update(int *buffer, int length)
int ret, cdda_bytes, mult = 1;
cdda_bytes = length*4;
if (PsndRate <= 22050 + 100) mult = 2;
if (PsndRate < 22050 - 100) mult = 4;
if (PicoIn.sndRate <= 22050 + 100) mult = 2;
if (PicoIn.sndRate < 22050 - 100) mult = 4;
cdda_bytes *= mult;
ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);
@ -270,12 +259,12 @@ void cdda_start_play(int lba_base, int lba_offset, int lb_len)
PICO_INTERNAL void PsndClear(void)
{
int len = PsndLen;
if (PsndLen_exc_add) len++;
int len = Pico.snd.len;
if (Pico.snd.len_e_add) len++;
if (PicoIn.opt & POPT_EN_STEREO)
memset32((int *) PsndOut, 0, len); // assume PsndOut to be aligned
memset32((int *) PicoIn.sndOut, 0, len); // assume PicoIn.sndOut to be aligned
else {
short *out = PsndOut;
short *out = PicoIn.sndOut;
if ((long)out & 2) { *out++ = 0; len--; }
memset32((int *) out, 0, len/2);
if (len & 1) out[len-1] = 0;
@ -294,7 +283,7 @@ static int PsndRender(int offset, int length)
pprof_start(sound);
if (PicoIn.AHW & PAHW_PICO) {
PicoPicoPCMUpdate(PsndOut+offset, length, stereo);
PicoPicoPCMUpdate(PicoIn.sndOut+offset, length, stereo);
return length;
}
@ -330,7 +319,7 @@ static int PsndRender(int offset, int length)
p32x_pwm_update(buf32, length, stereo);
// convert + limit to normal 16bit output
PsndMix_32_to_16l(PsndOut+offset, buf32, length);
PsndMix_32_to_16l(PicoIn.sndOut+offset, buf32, length);
pprof_end(sound);
@ -342,51 +331,50 @@ PICO_INTERNAL void PsndGetSamples(int y)
{
static int curr_pos = 0;
if (ym2612.dacen && PsndDacLine < y)
if (ym2612.dacen && Pico.snd.dac_line < y)
PsndDoDAC(y - 1);
PsndDoPSG(y - 1);
if (y == 224)
{
if (Pico.m.status & 2)
curr_pos += PsndRender(curr_pos, PsndLen-PsndLen/2);
else curr_pos = PsndRender(0, PsndLen_use);
curr_pos += PsndRender(curr_pos, Pico.snd.len-Pico.snd.len/2);
else curr_pos = PsndRender(0, Pico.snd.len_use);
if (Pico.m.status & 1)
Pico.m.status |= 2;
else Pico.m.status &= ~2;
if (PicoWriteSound)
PicoWriteSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
if (PicoIn.writeSound)
PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
// clear sound buffer
PsndClear();
PsndDacLine = 224;
Pico.snd.dac_line = 224;
dac_info[224] = 0;
}
else if (Pico.m.status & 3) {
Pico.m.status |= 2;
Pico.m.status &= ~1;
curr_pos = PsndRender(0, PsndLen/2);
curr_pos = PsndRender(0, Pico.snd.len/2);
}
}
PICO_INTERNAL void PsndGetSamplesMS(void)
{
int stereo = (PicoIn.opt & 8) >> 3;
int length = PsndLen_use;
int length = Pico.snd.len_use;
// PSG
if (PicoIn.opt & POPT_EN_PSG)
SN76496Update(PsndOut, length, stereo);
PsndDoPSG(223);
// upmix to "stereo" if needed
if (stereo) {
if (PicoIn.opt & POPT_EN_STEREO) {
int i, *p;
for (i = length, p = (void *)PsndOut; i > 0; i--, p++)
for (i = length, p = (void *)PicoIn.sndOut; i > 0; i--, p++)
*p |= *p << 16;
}
if (PicoWriteSound != NULL)
PicoWriteSound(length * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
if (PicoIn.writeSound != NULL)
PicoIn.writeSound(length * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
PsndClear();
dac_info[224] = 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View File

@ -227,6 +227,9 @@ static int state_save(void *file)
areaWrite(&ver, 1, 4, file);
if (!(PicoIn.AHW & PAHW_SMS)) {
// the patches can cause incompatible saves with no-idle
SekFinishIdleDet();
memset(buff, 0, sizeof(buff));
SekPackCpu(buff, 0);
CHECKED_WRITE_BUFF(CHUNK_M68K, buff);
@ -235,6 +238,9 @@ static int state_save(void *file)
CHECKED_WRITE_BUFF(CHUNK_IOPORTS, PicoMem.ioports);
ym2612_pack_state();
CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);
if (!(PicoIn.opt & POPT_DIS_IDLE_DET))
SekInitIdleDet();
}
else {
CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);

View File

@ -259,9 +259,9 @@ static int custom_read(menu_entry *me, const char *var, const char *val)
case MA_OPT_SOUND_QUALITY:
if (strcasecmp(var, "Sound Quality") != 0) return 0;
PsndRate = strtoul(val, &tmp, 10);
if (PsndRate < 8000 || PsndRate > 44100)
PsndRate = 22050;
PicoIn.sndRate = strtoul(val, &tmp, 10);
if (PicoIn.sndRate < 8000 || PicoIn.sndRate > 44100)
PicoIn.sndRate = 22050;
if (*tmp == 'H' || *tmp == 'h') tmp++;
if (*tmp == 'Z' || *tmp == 'z') tmp++;
while (*tmp == ' ') tmp++;

View File

@ -604,7 +604,7 @@ void emu_set_defconfig(void)
{
memcpy(&currentConfig, &defaultConfig, sizeof(currentConfig));
PicoIn.opt = currentConfig.s_PicoOpt;
PsndRate = currentConfig.s_PsndRate;
PicoIn.sndRate = currentConfig.s_PsndRate;
PicoIn.regionOverride = currentConfig.s_PicoRegion;
PicoIn.autoRgnOrder = currentConfig.s_PicoAutoRgnOrder;
}
@ -958,10 +958,10 @@ void emu_set_fastforward(int set_on)
static int set_Frameskip, set_EmuOpt, is_on = 0;
if (set_on && !is_on) {
set_PsndOut = PsndOut;
set_PsndOut = PicoIn.sndOut;
set_Frameskip = currentConfig.Frameskip;
set_EmuOpt = currentConfig.EmuOpt;
PsndOut = NULL;
PicoIn.sndOut = NULL;
currentConfig.Frameskip = 8;
currentConfig.EmuOpt &= ~4;
currentConfig.EmuOpt |= 0x40000;
@ -969,7 +969,7 @@ void emu_set_fastforward(int set_on)
emu_status_msg("FAST FORWARD");
}
else if (!set_on && is_on) {
PsndOut = set_PsndOut;
PicoIn.sndOut = set_PsndOut;
currentConfig.Frameskip = set_Frameskip;
currentConfig.EmuOpt = set_EmuOpt;
PsndRerate(1);
@ -1253,9 +1253,9 @@ void emu_init(void)
config_readlrom(path);
PicoInit();
PicoMessage = plat_status_msg_busy_next;
PicoMCDopenTray = emu_tray_open;
PicoMCDcloseTray = emu_tray_close;
PicoIn.osdMessage = plat_status_msg_busy_next;
PicoIn.mcdTrayOpen = emu_tray_open;
PicoIn.mcdTrayClose = emu_tray_close;
sndout_init();
}
@ -1285,12 +1285,12 @@ void emu_finish(void)
static void snd_write_nonblocking(int len)
{
sndout_write_nb(PsndOut, len);
sndout_write_nb(PicoIn.sndOut, len);
}
void emu_sound_start(void)
{
PsndOut = NULL;
PicoIn.sndOut = NULL;
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
{
@ -1299,12 +1299,12 @@ void emu_sound_start(void)
PsndRerate(Pico.m.frame_count ? 1 : 0);
printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
PsndRate, PsndLen, is_stereo, Pico.m.pal);
sndout_start(PsndRate, is_stereo);
PicoWriteSound = snd_write_nonblocking;
PicoIn.sndRate, Pico.snd.len, is_stereo, Pico.m.pal);
sndout_start(PicoIn.sndRate, is_stereo);
PicoIn.writeSound = snd_write_nonblocking;
plat_update_volume(0, 0);
memset(sndBuffer, 0, sizeof(sndBuffer));
PsndOut = sndBuffer;
PicoIn.sndOut = sndBuffer;
}
}

View File

@ -610,7 +610,7 @@ static int mh_opt_misc(int id, int keys)
{
switch (id) {
case MA_OPT_SOUND_QUALITY:
PsndRate = sndrate_prevnext(PsndRate, keys & PBTN_RIGHT);
PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, keys & PBTN_RIGHT);
break;
case MA_OPT_REGION:
region_prevnext(keys & PBTN_RIGHT);
@ -674,7 +674,7 @@ static const char *mgn_opt_sound(int id, int *offs)
const char *str2;
*offs = -8;
str2 = (PicoIn.opt & POPT_EN_STEREO) ? "stereo" : "mono";
sprintf(static_buff, "%5iHz %s", PsndRate, str2);
sprintf(static_buff, "%5iHz %s", PicoIn.sndRate, str2);
return static_buff;
}
@ -892,7 +892,7 @@ static void debug_menu_loop(void)
if (inp & PBTN_UP) pv->debug_p ^= PVD_KILL_S_HI;
if (inp & PBTN_MA2) pv->debug_p ^= PVD_KILL_32X;
if (inp & PBTN_MOK) {
PsndOut = NULL; // just in case
PicoIn.sndOut = NULL; // just in case
PicoIn.skipFrame = 1;
PicoFrame();
PicoIn.skipFrame = 0;

View File

@ -167,11 +167,11 @@ void mp3_update(int *buffer, int length, int stereo)
return;
length_mp3 = length;
if (PsndRate <= 11025 + 100) {
if (PicoIn.sndRate <= 11025 + 100) {
mix_samples = mix_16h_to_32_s2;
length_mp3 <<= 2; shr = 2;
}
else if (PsndRate <= 22050 + 100) {
else if (PicoIn.sndRate <= 22050 + 100) {
mix_samples = mix_16h_to_32_s1;
length_mp3 <<= 1; shr = 1;
}

View File

@ -266,12 +266,12 @@ static void stdbg(const char *fmt, ...)
static void updateSound(int len)
{
snd_all_samples += len / 2;
PsndOut += len / 2;
if (PsndOut - snd_cbuff >= snd_cbuf_samples)
PicoIn.sndOut += len / 2;
if (PicoIn.sndOut - snd_cbuff >= snd_cbuf_samples)
{
//if (PsndOut - snd_cbuff != snd_cbuf_samples)
// stdbg("snd diff is %i, not %i", PsndOut - snd_cbuff, snd_cbuf_samples);
PsndOut = snd_cbuff;
//if (PicoIn.sndOut - snd_cbuff != snd_cbuf_samples)
// stdbg("snd diff is %i, not %i", PicoIn.sndOut - snd_cbuff, snd_cbuf_samples);
PicoIn.sndOut = snd_cbuff;
}
}
@ -317,7 +317,7 @@ static void RunEvents(unsigned int which)
{
int do_it = 1;
if (PsndOut != NULL)
if (PicoIn.sndOut != NULL)
FrameworkAudio_SetPause(1);
if (giz_screen == NULL)
giz_screen = fb_lock(1);
@ -344,7 +344,7 @@ static void RunEvents(unsigned int which)
Sleep(0);
}
if (PsndOut != NULL)
if (PicoIn.sndOut != NULL)
FrameworkAudio_SetPause(0);
reset_timing = 1;
}
@ -401,7 +401,7 @@ static void updateKeys(void)
events = (allActions[0] | allActions[1]) >> 16;
// volume is treated in special way and triggered every frame
if ((events & 0x6000) && PsndOut != NULL)
if ((events & 0x6000) && PicoIn.sndOut != NULL)
{
int vol = currentConfig.volume;
if (events & 0x2000) {
@ -469,19 +469,19 @@ void pemu_loop(void)
if (PicoIn.AHW & PAHW_MCD) PicoCDBufferInit();
// prepare sound stuff
PsndOut = NULL;
PicoIn.sndOut = NULL;
if (currentConfig.EmuOpt & 4)
{
int ret, snd_excess_add, stereo;
if (PsndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
PsndRerate(Pico.m.frame_count ? 1 : 0);
}
stereo=(PicoIn.opt&8)>>3;
snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;
snd_cbuf_samples = (PsndRate<<stereo) * 16 / target_fps;
snd_excess_add = ((PicoIn.sndRate - Pico.snd.len*target_fps)<<16) / target_fps;
snd_cbuf_samples = (PicoIn.sndRate<<stereo) * 16 / target_fps;
lprintf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n",
PsndRate, PsndLen, snd_excess_add, stereo, Pico.m.pal);
ret = FrameworkAudio_Init(PsndRate, snd_cbuf_samples, stereo);
PicoIn.sndRate, Pico.snd.len, snd_excess_add, stereo, Pico.m.pal);
ret = FrameworkAudio_Init(PicoIn.sndRate, snd_cbuf_samples, stereo);
if (ret != 0) {
lprintf("FrameworkAudio_Init() failed: %i\n", ret);
sprintf(noticeMsg, "sound init failed (%i), snd disabled", ret);
@ -489,11 +489,11 @@ void pemu_loop(void)
currentConfig.EmuOpt &= ~4;
} else {
FrameworkAudio_SetVolume(currentConfig.volume, currentConfig.volume);
PicoWriteSound = updateSound;
PicoIn.writeSound = updateSound;
snd_cbuff = FrameworkAudio_56448Buffer();
PsndOut = snd_cbuff + snd_cbuf_samples / 2; // start writing at the middle
PicoIn.sndOut = snd_cbuff + snd_cbuf_samples / 2; // start writing at the middle
snd_all_samples = 0;
PsndRate_old = PsndRate;
PsndRate_old = PicoIn.sndRate;
PicoOpt_old = PicoIn.opt;
pal_old = Pico.m.pal;
}
@ -553,14 +553,14 @@ void pemu_loop(void)
//tval_thissec += 1000;
tval_thissec += sec_ms;
if (PsndOut != NULL)
if (PicoIn.sndOut != NULL)
{
/* some code which tries to sync things to audio clock, the dirty way */
static int audio_skew_prev = 0;
int audio_skew, adj, co = 9, shift = 7;
audio_skew = snd_all_samples*2 - FrameworkAudio_BufferPos();
if (PsndRate == 22050) co = 10;
if (PsndRate > 22050) co = 11;
if (PicoIn.sndRate == 22050) co = 10;
if (PicoIn.sndRate > 22050) co = 11;
if (PicoIn.opt&8) shift++;
if (audio_skew < 0) {
adj = -((-audio_skew) >> shift);
@ -600,7 +600,7 @@ void pemu_loop(void)
for (i = 0; i < currentConfig.Frameskip; i++) {
updateKeys();
SkipFrame(); frames_done++;
if (PsndOut) { // do framelimitting if sound is enabled
if (PicoIn.sndOut) { // do framelimitting if sound is enabled
int tval_diff;
tval = GetTickCount();
tval_diff = (int)(tval - tval_thissec) << 8;
@ -660,7 +660,7 @@ void pemu_loop(void)
if (currentConfig.Frameskip < 0 && tval_diff - lim_time >= (300<<8)) // slowdown detection
reset_timing = 1;
else if (PsndOut != NULL || currentConfig.Frameskip < 0)
else if (PicoIn.sndOut != NULL || currentConfig.Frameskip < 0)
{
// sleep if we are still too fast
if (tval_diff < lim_time)
@ -676,8 +676,8 @@ void pemu_loop(void)
if (PicoIn.AHW & PAHW_MCD) PicoCDBufferFree();
if (PsndOut != NULL) {
PsndOut = snd_cbuff = NULL;
if (PicoIn.sndOut != NULL) {
PicoIn.sndOut = snd_cbuff = NULL;
FrameworkAudio_Close();
}

View File

@ -1046,7 +1046,7 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
break;
case MA_OPT_SOUND_QUALITY:
str = (PicoIn.opt&0x08)?"stereo":"mono";
text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);
text_out16(x, y, "Sound Quality: %5iHz %s", PicoIn.sndRate, str);
break;
case MA_OPT_REGION:
text_out16(x, y, "Region: %s", me_region_name(PicoIn.regionOverride, PicoIn.autoRgnOrder));
@ -1174,18 +1174,18 @@ static int menu_loop_options(void)
}
break;
case MA_OPT_SOUND_QUALITY:
if ((inp & PBTN_RIGHT) && PsndRate == 44100 &&
if ((inp & PBTN_RIGHT) && PicoIn.sndRate == 44100 &&
!(PicoIn.opt&0x08))
{
PsndRate = 11025;
PicoIn.sndRate = 11025;
PicoIn.opt |= 8;
} else if ((inp & PBTN_LEFT) && PsndRate == 11025 &&
} else if ((inp & PBTN_LEFT) && PicoIn.sndRate == 11025 &&
(PicoIn.opt&0x08) && !(PicoIn.AHW&1))
{
PsndRate = 44100;
PicoIn.sndRate = 44100;
PicoIn.opt &= ~8;
} else
PsndRate = sndrate_prevnext(PsndRate, inp & PBTN_RIGHT);
PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, inp & PBTN_RIGHT);
break;
case MA_OPT_REGION:
region_prevnext(inp & PBTN_RIGHT);

View File

@ -402,9 +402,9 @@ int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)
writebuff_ptr = 0;
/* predict sample counter for next frame */
if (PsndLen_exc_add) {
length = PsndLen;
if (PsndLen_exc_cnt + PsndLen_exc_add >= 0x10000) length++;
if (Pico.snd.len_e_add) {
length = Pico.snd.len;
if (Pico.snd.len_e_cnt + Pico.snd.len_e_add >= 0x10000) length++;
}
/* give 940 ym job */
@ -463,11 +463,11 @@ int mp3dec_start(FILE *f, int fpos_start)
if (loaded_mp3 != f)
{
if (PicoMessage != NULL)
if (PicoIn.osdMessage != NULL)
{
fseek(f, 0, SEEK_END);
if (ftell(f) > 2*1024*1024)
PicoMessage("Loading MP3...");
PicoIn.osdMessage("Loading MP3...");
}
fseek(f, 0, SEEK_SET);
fread(mp3_mem, 1, MP3_SIZE_MAX, f);

View File

@ -692,7 +692,7 @@ void pemu_sound_start(void)
{
soc = soc_detect();
if (soc == SOCID_POLLUX) {
PsndRate = pollux_get_real_snd_rate(PsndRate);
PicoIn.sndRate = pollux_get_real_snd_rate(PicoIn.sndRate);
PsndRerate(Pico.m.frame_count ? 1 : 0);
}
@ -707,10 +707,10 @@ void pemu_sound_stop(void)
int i;
/* get back from Pollux pain */
PsndRate += 1000;
PicoIn.sndRate += 1000;
for (i = 0; i < ARRAY_SIZE(sound_rates); i++) {
if (PsndRate >= sound_rates[i]) {
PsndRate = sound_rates[i];
if (PicoIn.sndRate >= sound_rates[i]) {
PicoIn.sndRate = sound_rates[i];
break;
}
}

@ -1 +1 @@
Subproject commit f287890d65ad36ca75bb71d05745693ae78b1490
Subproject commit 21082d0b2b9910727770674cef9b68b9e97a3155

View File

@ -1088,9 +1088,9 @@ bool retro_load_game(const struct retro_game_info *info)
PicoLoopPrepare();
PicoWriteSound = snd_write;
PicoIn.writeSound = snd_write;
memset(sndBuffer, 0, sizeof(sndBuffer));
PsndOut = sndBuffer;
PicoIn.sndOut = sndBuffer;
PsndRerate(0);
return true;
@ -1193,7 +1193,7 @@ static const unsigned short retro_pico_map[] = {
static void snd_write(int len)
{
audio_batch_cb(PsndOut, len / 4);
audio_batch_cb(PicoIn.sndOut, len / 4);
}
static enum input_device input_name_to_val(const char *name)
@ -1375,7 +1375,7 @@ void retro_init(void)
#endif
PicoIn.opt |= POPT_EN_DRC;
#endif
PsndRate = 44100;
PicoIn.sndRate = 44100;
PicoIn.autoRgnOrder = 0x184; // US, EU, JP
vout_width = 320;
@ -1390,9 +1390,9 @@ void retro_init(void)
PicoDrawSetOutFormat(PDF_RGB555, 0);
PicoDrawSetOutBuf(vout_buf, vout_width * 2);
//PicoMessage = plat_status_msg_busy_next;
PicoMCDopenTray = disk_tray_open;
PicoMCDcloseTray = disk_tray_close;
//PicoIn.osdMessage = plat_status_msg_busy_next;
PicoIn.mcdTrayOpen = disk_tray_open;
PicoIn.mcdTrayClose = disk_tray_close;
update_variables();
}

View File

@ -29,7 +29,7 @@ void pemu_prep_defconfig(void)
void pemu_validate_config(void)
{
#ifndef __arm__
#if !defined(__arm__) && !defined(__i386__) && !defined(__x86_64__)
PicoIn.opt &= ~POPT_EN_DRC;
#endif
}

View File

@ -571,32 +571,32 @@ void pemu_sound_start(void)
samples_made = samples_done = 0;
if (PsndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
PsndRerate(Pico.m.frame_count ? 1 : 0);
}
stereo=(PicoIn.opt&8)>>3;
samples_block = Pico.m.pal ? SOUND_BLOCK_SIZE_PAL : SOUND_BLOCK_SIZE_NTSC;
if (PsndRate <= 22050) samples_block /= 2;
if (PicoIn.sndRate <= 22050) samples_block /= 2;
sndBuffer_endptr = &sndBuffer[samples_block*SOUND_BLOCK_COUNT];
lprintf("starting audio: %i, len: %i, stereo: %i, pal: %i, block samples: %i\n",
PsndRate, PsndLen, stereo, Pico.m.pal, samples_block);
PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block);
// while (sceAudioOutput2GetRestSample() > 0) psp_msleep(100);
// sceAudio_5C37C0AE();
ret = sceAudio_38553111(samples_block/2, PsndRate, 2); // seems to not need that stupid 64byte alignment
ret = sceAudio_38553111(samples_block/2, PicoIn.sndRate, 2); // seems to not need that stupid 64byte alignment
if (ret < 0) {
lprintf("sceAudio_38553111() failed: %i\n", ret);
emu_status_msg("sound init failed (%i), snd disabled", ret);
currentConfig.EmuOpt &= ~EOPT_EN_SOUND;
} else {
PicoWriteSound = writeSound;
PicoIn.writeSound = writeSound;
memset32((int *)(void *)sndBuffer, 0, sizeof(sndBuffer)/4);
snd_playptr = sndBuffer_endptr - samples_block;
samples_made = samples_block; // send 1 empty block first..
PsndOut = sndBuffer;
PsndRate_old = PsndRate;
PicoIn.sndOut = sndBuffer;
PsndRate_old = PicoIn.sndRate;
PicoOpt_old = PicoIn.opt;
pal_old = Pico.m.pal;
}
@ -641,16 +641,16 @@ static void writeSound(int len)
{
int ret;
PsndOut += len / 2;
/*if (PsndOut > sndBuffer_endptr) {
memcpy32((int *)(void *)sndBuffer, (int *)endptr, (PsndOut - endptr + 1) / 2);
PsndOut = &sndBuffer[PsndOut - endptr];
PicoIn.sndOut += len / 2;
/*if (PicoIn.sndOut > sndBuffer_endptr) {
memcpy32((int *)(void *)sndBuffer, (int *)endptr, (PicoIn.sndOut - endptr + 1) / 2);
PicoIn.sndOut = &sndBuffer[PicoIn.sndOut - endptr];
lprintf("mov\n");
}
else*/
if (PsndOut > sndBuffer_endptr) lprintf("snd oflow %i!\n", PsndOut - sndBuffer_endptr);
if (PsndOut >= sndBuffer_endptr)
PsndOut = sndBuffer;
if (PicoIn.sndOut > sndBuffer_endptr) lprintf("snd oflow %i!\n", PicoIn.sndOut - sndBuffer_endptr);
if (PicoIn.sndOut >= sndBuffer_endptr)
PicoIn.sndOut = sndBuffer;
// signal the snd thread
samples_made += len / 2;
@ -873,7 +873,7 @@ void pemu_loop(void)
}
// prepare sound stuff
PsndOut = NULL;
PicoIn.sndOut = NULL;
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
{
pemu_sound_start();
@ -1021,9 +1021,9 @@ void pemu_loop(void)
if (PicoIn.AHW & PAHW_MCD) PicoCDBufferFree();
if (PsndOut != NULL) {
if (PicoIn.sndOut != NULL) {
pemu_sound_stop();
PsndOut = NULL;
PicoIn.sndOut = NULL;
}
// save SRAM

View File

@ -1227,7 +1227,7 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
break;
case MA_OPT_SOUND_QUALITY:
str = (PicoIn.opt&0x08)?"stereo":"mono";
text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);
text_out16(x, y, "Sound Quality: %5iHz %s", PicoIn.sndRate, str);
break;
case MA_OPT_REGION:
text_out16(x, y, "Region: %s", me_region_name(PicoIn.regionOverride, PicoIn.autoRgnOrder));
@ -1353,7 +1353,7 @@ static int menu_loop_options(void)
}
break;
case MA_OPT_SOUND_QUALITY:
PsndRate = sndrate_prevnext(PsndRate, inp & PBTN_RIGHT);
PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, inp & PBTN_RIGHT);
break;
case MA_OPT_REGION:
region_prevnext(inp & PBTN_RIGHT);

View File

@ -403,8 +403,8 @@ void mp3_update(int *buffer, int length, int stereo)
if (mp3_handle < 0 || mp3_src_pos >= mp3_src_size) return;
length_mp3 = length;
if (PsndRate == 22050) length_mp3 <<= 1; // mp3s are locked to 44100Hz stereo
else if (PsndRate == 11025) length_mp3 <<= 2; // so make length 44100ish
if (PicoIn.sndRate == 22050) length_mp3 <<= 1; // mp3s are locked to 44100Hz stereo
else if (PicoIn.sndRate == 11025) length_mp3 <<= 2; // so make length 44100ish
/* do we have to wait? */
if (mp3_job_started && mp3_samples_ready < length_mp3)
@ -420,8 +420,8 @@ void mp3_update(int *buffer, int length, int stereo)
{
int shr = 0;
void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;
if (PsndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }
else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }
if (PicoIn.sndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }
else if (PicoIn.sndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }
if (1152 - mp3_buffer_offs >= length_mp3) {
mix_samples(buffer, mp3_mix_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length<<1);

View File

@ -131,7 +131,7 @@ void pemu_sound_start(void)
{
int ret;
PsndOut = NULL;
PicoIn.sndOut = NULL;
currentConfig.EmuOpt &= ~EOPT_EXT_FRMLIMIT;
// prepare sound stuff
@ -139,14 +139,14 @@ void pemu_sound_start(void)
{
PsndRerate(0);
ret = DSoundInit(FrameWnd, PsndRate, (PicoIn.opt & POPT_EN_STEREO) ? 1 : 0, PsndLen);
ret = DSoundInit(FrameWnd, PicoIn.sndRate, (PicoIn.opt & POPT_EN_STEREO) ? 1 : 0, Pico.snd.len);
if (ret != 0) {
lprintf("dsound init failed\n");
return;
}
PsndOut = (void *)sndbuff;
PicoWriteSound = update_sound;
PicoIn.sndOut = (void *)sndbuff;
PicoIn.writeSound = update_sound;
currentConfig.EmuOpt |= EOPT_EXT_FRMLIMIT;
}
}

View File

@ -58,7 +58,7 @@ int main(int argc, char *argv[])
DUMP_EST(f, Pico);
DUMP_EST(f, PicoMem_vram);
DUMP_EST(f, PicoMem_cram);
DUMP_EST(f, PicoIn.opt);
DUMP_EST(f, PicoOpt);
DUMP_EST(f, Draw2FB);
DUMP_EST(f, HighPal);
DUMP_PMEM(f, vram);