ifeq "$(DEBUG)" "0"
CFLAGS += -O3 -DNDEBUG
endif
-ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","gp2x" "opendingux" "rpi1"))
-# very small caches, avoid optimization options making the binary much bigger
-CFLAGS += -finline-limit=42 -fno-unroll-loops -fno-ipa-cp-clone # -fno-ipa-cp
-endif
# This is actually needed, bevieve me.
# If you really have to disable this, set NO_ALIGN_FUNCTIONS elsewhere.
config.mak:
endif
+ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","gp2x" "opendingux" "rpi1"))
+# very small caches, avoid optimization options making the binary much bigger
+CFLAGS += -finline-limit=42 -fno-unroll-loops -fno-ipa-cp -fno-common -fno-stack-protector -ffast-math
+endif
+
# default settings
ifeq "$(ARCH)" "arm"
use_cyclone ?= 1
platform|toolchain|configure command
--------|---------|-----------------
-gp2x,wiz,caanoo|open2x|CROSS_COMPILE=arm-open2x-linux- CFLAGS="-I$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/include -fno-stack-protector -fno-common" LDFLAGS="--sysroot $TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux -L$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib" ./configure --platform=gp2x
-gp2x,wiz,caanoo|open2x with ubuntu arm gcc 4.7|CROSS_COMPILE=arm-linux-gnueabi- CFLAGS="-I$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/include -fno-stack-protector -fno-common" LDFLAGS="-B$TC/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1 -B$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib -L$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib" ./configure --platform=gp2x
+gp2x,wiz,caanoo|open2x|CROSS_COMPILE=arm-open2x-linux- CFLAGS="-I$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/include" LDFLAGS="--sysroot $TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux -L$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib" ./configure --platform=gp2x
+gp2x,wiz,caanoo|open2x with ubuntu arm gcc 4.7|CROSS_COMPILE=arm-linux-gnueabi- CFLAGS="-I$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/include" LDFLAGS="-B$TC/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1 -B$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib -L$TC/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/lib" ./configure --platform=gp2x
opendingux|opendingux|CROSS_COMPILE=mipsel-linux- CFLAGS="-I$TC/usr/include -I$TC/usr/include/SDL" LDFLAGS="--sysroot $TC -L$TC/lib" ./configure --platform=opendingux
opendingux|opendingux with ubuntu mips gcc 5.4|CROSS_COMPILE=mipsel-linux-gnu- CFLAGS="-I$TC/usr/include -I$TC/usr/include/SDL" LDFLAGS="-B$TC/usr/lib -B$TC/lib -Wl,-rpath-link=$TC/usr/lib -Wl,-rpath-link=$TC/lib" ./configure --platform=opendingux
gcw0|gcw0|CROSS_COMPILE=mipsel-gcw0-linux-uclibc- CFLAGS="-I$TC/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include -I$TC/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include/SDL" LDFLAGS="--sysroot $TC/usr/mipsel-gcw0-linux-uclibc/sysroot" ./configure --platform=gcw0
int t2 = rcache_get_tmp(); \
int t3 = rcache_get_tmp(); \
/* if (sr < 0) return */ \
- emith_asrf(t2, sr, 12); \
+ emith_cmp_r_imm(sr, 0); \
EMITH_JMP_START(DCOND_LE); \
/* turns = sr.cycles / cycles */ \
+ emith_asr(t2, sr, 12); \
emith_move_r_imm(t3, (u32)((1ULL<<32) / (cycles)) + 1); \
emith_mul_u64(t1, t2, t2, t3); /* multiply by 1/x */ \
rcache_free_tmp(t3); \
#define emith_adc_r_r(d, s) \
emith_adc_r_r_r(d, d, s)
-// NB: the incoming C can cause its own outgoing C if s2+C=0 (or s1+C=0 FWIW)
-// moreover, s2 is 0 if there is C, so no other C can be generated.
+// NB: the incoming carry Cin can cause Cout if s2+Cin=0 (or s1+Cin=0 FWIW)
+// moreover, if s2+Cin=0 caused Cout, s1+s2+Cin=s1+0 can't cause another Cout
#define emith_adcf_r_r_r(d, s1, s2) do { \
emith_add_r_r_r(FNZ, s2, FC); \
EMIT(MIPS_SLTU_REG(AT, FNZ, FC)); \
/*
* Basic macros to emit x86 instructions and some utils
* Copyright (C) 2008,2009,2010 notaz
- * Copyright (C) 2019 kuv
+ * Copyright (C) 2019 kub
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
}
#define STEP_LS 24
-#define STEP_N 440
+#define STEP_N 488 // one line
#define sync_sh2s_normal p32x_sync_sh2s
//#define sync_sh2s_lockstep p32x_sync_sh2s
{
int hix = (a >> 1) % PFIFO_CNT;
struct sh2_poll_fifo *fifo = sh2_poll_fifo[hix];
- struct sh2_poll_fifo *q = &fifo[(sh2_poll_wr[hix]-1) % PFIFO_SZ];
+ struct sh2_poll_fifo *q;
int cpu = sh2 ? sh2->is_slave : -1;
unsigned rd = sh2_poll_rd[hix], wr = sh2_poll_wr[hix];
unsigned idx, nrd;
// throw out any values written by other cpus, plus heading cancelled stuff
for (idx = nrd = wr; idx != rd; ) {
idx = (idx-1) % PFIFO_SZ;
- if (fifo[idx].a == a && fifo[idx].cpu != cpu) { fifo[idx].a = -1; }
- if (fifo[idx].a != -1) { nrd = idx; }
+ q = &fifo[idx];
+ if (q->cpu != cpu && q->a == a) { q->a = -1; }
+ if (q->a != -1) { nrd = idx; }
}
rd = nrd;
// intermediate values that may cause synchronisation problems.
// NB this can take an eternity on m68k: mov.b <addr1.l>,<addr2.l> needs
// 28 m68k-cycles (~80 sh2-cycles) to complete (observed in Metal Head)
- if (q->a == a && rd != wr && !CYCLES_GT(cycles,q->cycles+30)) {
+ q = &fifo[(sh2_poll_wr[hix]-1) % PFIFO_SZ];
+ if (rd != wr && q->a == a && !CYCLES_GT(cycles,q->cycles+30)) {
q->d = d;
} else {
// store write to poll address in fifo
case 0x1d:
case 0x1e:
case 0x1f:
+ return;
+ case 0x20: // comm port
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ if (REG8IN16(r, a) != d) {
+ int cycles = SekCyclesDone();
+
+ if (cycles - (int)msh2.m68krcycles_done > 30)
+ 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);
+ sh2_poll_write(a & ~1, r[a / 2], cycles, NULL);
+ }
+ return;
case 0x30:
return;
case 0x31: // PWM control
p32x_pwm_write16(a & ~1, d, NULL, SekCyclesDone());
return;
}
-
- if ((a & 0x30) == 0x20) {
- int cycles = SekCyclesDone();
-
- if (REG8IN16(r, a) == d)
- return;
-
- if (cycles - (int)msh2.m68krcycles_done > 30)
- 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);
- sh2_poll_write(a & ~1, r[a / 2], cycles, NULL);
- return;
- }
}
static void p32x_reg_write16(u32 a, u32 d)
// for things like bset on comm port
m68k_poll.cnt = 0;
- switch (a) {
- case 0x00: // adapter ctl
+ switch (a/2) {
+ case 0x00/2: // adapter ctl
if ((d ^ r[0]) & d & P32XS_nRES)
p32x_reset_sh2s();
r[0] &= ~(P32XS_FM|P32XS_nRES|P32XS_ADEN);
r[0] |= d & (P32XS_FM|P32XS_nRES|P32XS_ADEN);
return;
- case 0x08: // DREQ src
+ case 0x08/2: // DREQ src
r[a / 2] = d & 0xff;
return;
- case 0x0a:
+ case 0x0a/2:
r[a / 2] = d & ~1;
return;
- case 0x0c: // DREQ dest
+ case 0x0c/2: // DREQ dest
r[a / 2] = d & 0xff;
return;
- case 0x0e:
+ case 0x0e/2:
r[a / 2] = d;
return;
- case 0x10: // DREQ len
+ case 0x10/2: // DREQ len
r[a / 2] = d & ~3;
return;
- case 0x12: // FIFO reg
+ case 0x12/2: // FIFO reg
dreq0_write(r, d);
return;
- case 0x1a: // TV + mystery bit
+ case 0x1a/2: // TV + mystery bit
r[a / 2] = d & 0x0101;
return;
- case 0x30: // PWM control
+ case 0x20/2: // comm port
+ case 0x22/2:
+ case 0x24/2:
+ case 0x26/2:
+ case 0x28/2:
+ case 0x2a/2:
+ case 0x2c/2:
+ case 0x2e/2:
+ if (r[a / 2] != d) {
+ int cycles = SekCyclesDone();
+
+ if (cycles - (int)msh2.m68krcycles_done > 30)
+ 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);
+ sh2_poll_write(a, (u16)d, cycles, NULL);
+ }
+ return;
+ case 0x30/2: // PWM control
d = (r[a / 2] & ~0x0f) | (d & 0x0f);
r[a / 2] = d;
p32x_pwm_write16(a, d, NULL, SekCyclesDone());
return;
- }
-
- // comm port
- if ((a & 0x30) == 0x20) {
- int cycles = SekCyclesDone();
-
- if (r[a / 2] == d)
- return;
-
- if (cycles - (int)msh2.m68krcycles_done > 30)
- 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);
- sh2_poll_write(a, (u16)d, cycles, NULL);
- return;
- }
- // PWM
- else if ((a & 0x30) == 0x30) {
- p32x_pwm_write16(a, d, NULL, SekCyclesDone());
- return;
+ case 0x32/2:
+ case 0x34/2:
+ case 0x36/2:
+ case 0x38/2:
+ case 0x3a/2:
+ case 0x3c/2:
+ case 0x3e/2:
+ p32x_pwm_write16(a, d, NULL, SekCyclesDone());
+ return;
}
p32x_reg_write8(a + 1, d);
u16 *r = Pico32x.regs;
a &= 0x3e;
- switch (a) {
- case 0x00: // adapter/irq ctl
+ switch (a/2) {
+ case 0x00/2: // adapter/irq ctl
return (r[0] & P32XS_FM) | Pico32x.sh2_regs[0]
| Pico32x.sh2irq_mask[sh2->is_slave];
- case 0x04: // H count (often as comm too)
+ case 0x04/2: // H count (often as comm too)
sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 9);
sh2s_sync_on_read(sh2);
return sh2_poll_read(a, Pico32x.sh2_regs[4 / 2], sh2_cycles_done_m68k(sh2), sh2);
- case 0x06:
+ case 0x06/2:
return (r[a / 2] & ~P32XS_FULL) | 0x4000;
- case 0x08: // DREQ src
- case 0x0a:
- case 0x0c: // DREQ dst
- case 0x0e:
- case 0x10: // DREQ len
+ case 0x08/2: // DREQ src
+ case 0x0a/2:
+ case 0x0c/2: // DREQ dst
+ case 0x0e/2:
+ case 0x10/2: // DREQ len
return r[a / 2];
- case 0x12: // DREQ FIFO - does this work on hw?
+ case 0x12/2: // DREQ FIFO - does this work on hw?
if (Pico32x.dmac0_fifo_ptr > 0) {
Pico32x.dmac0_fifo_ptr--;
r[a / 2] = Pico32x.dmac_fifo[0];
Pico32x.dmac0_fifo_ptr * 2);
}
return r[a / 2];
- case 0x14:
- case 0x16:
- case 0x18:
- case 0x1a:
- case 0x1c:
+ case 0x14/2:
+ case 0x16/2:
+ case 0x18/2:
+ case 0x1a/2:
+ case 0x1c/2:
return 0; // ?
+ case 0x20/2: // comm port
+ case 0x22/2:
+ case 0x24/2:
+ case 0x26/2:
+ case 0x28/2:
+ case 0x2a/2:
+ case 0x2c/2:
+ case 0x2e/2:
+ sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 9);
+ sh2s_sync_on_read(sh2);
+ return sh2_poll_read(a, r[a / 2], sh2_cycles_done_m68k(sh2), sh2);
+ case 0x30/2: // PWM
+ case 0x32/2:
+ case 0x34/2:
+ case 0x36/2:
+ case 0x38/2:
+ case 0x3a/2:
+ case 0x3c/2:
+ case 0x3e/2:
+ return p32x_pwm_read16(a, sh2, sh2_cycles_done_m68k(sh2));
}
- // comm port
- if ((a & 0x30) == 0x20) {
- sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 9);
- sh2s_sync_on_read(sh2);
- return sh2_poll_read(a, r[a / 2], sh2_cycles_done_m68k(sh2), sh2);
- }
- if ((a & 0x30) == 0x30)
- return p32x_pwm_read16(a, sh2, sh2_cycles_done_m68k(sh2));
-
elprintf_sh2(sh2, EL_32X|EL_ANOMALY,
"unhandled sysreg r16 [%02x] @%08x", a, sh2_pc(sh2));
return 0;
sh2_poll_write(a & ~1, d, cycles, sh2);
}
return;
+ case 0x20: // comm port
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ if (REG8IN16(r, a) != d) {
+ unsigned int cycles = sh2_cycles_done_m68k(sh2);
+
+ REG8IN16(r, a) = d;
+ sh2_end_run(sh2, 1);
+ p32x_m68k_poll_event(P32XF_68KCPOLL);
+ p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
+ sh2_poll_write(a & ~1, r[a / 2], cycles, sh2);
+ }
+ return;
case 0x30:
REG8IN16(r, a) = d & 0x0f;
d = r[0x30 / 2];
return;
}
- if ((a & 0x30) == 0x20) {
- unsigned int cycles;
- if (REG8IN16(r, a) == d)
- return;
-
- REG8IN16(r, a) = d;
- cycles = sh2_cycles_done_m68k(sh2);
- sh2_end_run(sh2, 1);
- p32x_m68k_poll_event(P32XF_68KCPOLL);
- p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
- sh2_poll_write(a & ~1, r[a / 2], cycles, sh2);
- return;
- }
-
elprintf(EL_32X|EL_ANOMALY,
"unhandled sysreg w8 [%02x] %02x @%08x", a, d, sh2_pc(sh2));
}
sh2->poll_cnt = 0;
- // comm
- if ((a & 0x30) == 0x20) {
- unsigned int cycles;
- if (Pico32x.regs[a / 2] == d)
- return;
-
- Pico32x.regs[a / 2] = d;
- cycles = sh2_cycles_done_m68k(sh2);
- sh2_end_run(sh2, 1);
- p32x_m68k_poll_event(P32XF_68KCPOLL);
- p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
- sh2_poll_write(a, d, cycles, sh2);
- return;
- }
- // PWM
- else if ((a & 0x30) == 0x30) {
- p32x_pwm_write16(a, d, sh2, sh2_cycles_done_m68k(sh2));
- return;
- }
-
- switch (a) {
- case 0: // FM
+ switch (a/2) {
+ case 0x00/2: // FM
Pico32x.regs[0] &= ~P32XS_FM;
Pico32x.regs[0] |= d & P32XS_FM;
break;
- case 0x14:
+ case 0x14/2:
Pico32x.sh2irqs &= ~P32XI_VRES;
goto irls;
- case 0x16:
+ case 0x16/2:
Pico32x.sh2irqi[sh2->is_slave] &= ~P32XI_VINT;
goto irls;
- case 0x18:
+ case 0x18/2:
Pico32x.sh2irqi[sh2->is_slave] &= ~P32XI_HINT;
goto irls;
- case 0x1a:
+ case 0x1a/2:
Pico32x.regs[2 / 2] &= ~(1 << sh2->is_slave);
p32x_update_cmd_irq(sh2, 0);
return;
- case 0x1c:
+ case 0x1c/2:
p32x_pwm_sync_to_sh2(sh2);
Pico32x.sh2irqi[sh2->is_slave] &= ~P32XI_PWM;
p32x_pwm_schedule_sh2(sh2);
goto irls;
+ case 0x20/2: // comm port
+ case 0x22/2:
+ case 0x24/2:
+ case 0x26/2:
+ case 0x28/2:
+ case 0x2a/2:
+ case 0x2c/2:
+ case 0x2e/2:
+ if (Pico32x.regs[a / 2] != d) {
+ unsigned int cycles = sh2_cycles_done_m68k(sh2);
+
+ Pico32x.regs[a / 2] = d;
+ sh2_end_run(sh2, 1);
+ p32x_m68k_poll_event(P32XF_68KCPOLL);
+ p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
+ sh2_poll_write(a, d, cycles, sh2);
+ }
+ return;
+ case 0x30/2: // PWM
+ case 0x32/2:
+ case 0x34/2:
+ case 0x36/2:
+ case 0x38/2:
+ case 0x3a/2:
+ case 0x3c/2:
+ case 0x3e/2:
+ p32x_pwm_write16(a, d, sh2, sh2_cycles_done_m68k(sh2));
+ return;
}
p32x_sh2reg_write8(a | 1, d, sh2);
sh2_burn_cycles(sh2, 1*2);
- // 0x3ffc0 is veridied
+ // 0x3ffc0 is verified
if ((a & 0x3ffc0) == 0x4000) {
d = p32x_sh2reg_read16(a, sh2);
goto out_16to8;
elprintf_sh2(sh2, EL_32X, "w8 [%08x] %02x @%06x",
a, d & 0xff, sh2_pc(sh2));
+ if ((a & 0x3ffc0) == 0x4000) {
+ p32x_sh2reg_write8(a, d, sh2);
+ goto out;
+ }
+
if (Pico32x.regs[0] & P32XS_FM) {
if ((a & 0x3fff0) == 0x4100) {
sh2->poll_cnt = 0;
}
}
- if ((a & 0x3ffc0) == 0x4000) {
- p32x_sh2reg_write8(a, d, sh2);
- goto out;
- }
-
sh2_write8_unmapped(a, d, sh2);
out:
DRC_RESTORE_SR(sh2);
elprintf_sh2(sh2, EL_32X, "w16 [%08x] %04x @%06x",
a, d & 0xffff, sh2_pc(sh2));
+ if ((a & 0x3ffc0) == 0x4000) {
+ p32x_sh2reg_write16(a, d, sh2);
+ goto out;
+ }
+
if (Pico32x.regs[0] & P32XS_FM) {
if ((a & 0x3fff0) == 0x4100) {
sh2->poll_cnt = 0;
}
}
- if ((a & 0x3ffc0) == 0x4000) {
- p32x_sh2reg_write16(a, d, sh2);
- goto out;
- }
-
sh2_write16_unmapped(a, d, sh2);
out:
DRC_RESTORE_SR(sh2);
\r
.text\r
\r
+#if 0\r
@ u32 a, SH2 *sh2\r
.global sh2_read8_rom\r
.global sh2_read8_sdram\r
.global sh2_read32_sdram\r
.global sh2_read32_da\r
.global sh2_read32_dram\r
+#endif\r
\r
@ u32 a, u32 d, SH2 *sh2\r
.global sh2_write8_sdram\r
*/
#include "../pico_int.h"
-static int pwm_cycles;
-static int pwm_mult;
-static int pwm_ptr;
-static int pwm_irq_reload;
-static int pwm_doing_fifo;
-static int pwm_silent;
+static struct {
+ int cycles;
+ int mult;
+ int ptr;
+ int irq_reload;
+ int doing_fifo;
+ int silent;
+ short current[2];
+} pwm;
void p32x_pwm_ctl_changed(void)
{
int cycles = Pico32x.regs[0x32 / 2];
cycles = (cycles - 1) & 0x0fff;
- pwm_cycles = cycles;
+ pwm.cycles = cycles;
// supposedly we should stop FIFO when xMd is 0,
// but mars test disagrees
- pwm_mult = 0;
+ pwm.mult = 0;
if ((control & 0x0f) != 0)
- pwm_mult = 0x10000 / cycles;
+ pwm.mult = 0x10000 / cycles;
- pwm_irq_reload = (control & 0x0f00) >> 8;
- pwm_irq_reload = ((pwm_irq_reload - 1) & 0x0f) + 1;
+ pwm.irq_reload = (control & 0x0f00) >> 8;
+ pwm.irq_reload = ((pwm.irq_reload - 1) & 0x0f) + 1;
if (Pico32x.pwm_irq_cnt == 0)
- Pico32x.pwm_irq_cnt = pwm_irq_reload;
+ Pico32x.pwm_irq_cnt = pwm.irq_reload;
}
static void do_pwm_irq(SH2 *sh2, unsigned int m68k_cycles)
p32x_trigger_irq(sh2, m68k_cycles, P32XI_PWM);
if (Pico32x.regs[0x30 / 2] & P32XP_RTP) {
- p32x_event_schedule(m68k_cycles, P32X_EVENT_PWM, pwm_cycles / 3 + 1);
+ p32x_event_schedule(m68k_cycles, P32X_EVENT_PWM, pwm.cycles / 3 + 1);
// note: might recurse
p32x_dreq1_trigger();
}
{
if (v == 0)
return 0;
- if (v > pwm_cycles)
- v = pwm_cycles;
- return ((int)v - pwm_cycles / 2) * pwm_mult;
+ if (v > pwm.cycles)
+ v = pwm.cycles;
+ return (v * 2 - pwm.cycles) / 2 * pwm.mult;
}
#define consume_fifo(sh2, m68k_cycles) { \
int cycles_diff = ((m68k_cycles) * 3) - Pico32x.pwm_cycle_p; \
- if (cycles_diff >= pwm_cycles) \
+ if (cycles_diff >= pwm.cycles) \
consume_fifo_do(sh2, m68k_cycles, cycles_diff); \
}
unsigned short *fifo_r = mem->pwm_fifo[1];
int sum = 0;
- if (pwm_cycles == 0 || pwm_doing_fifo)
+ if (pwm.cycles == 0 || pwm.doing_fifo)
return;
elprintf(EL_PWM, "pwm: %u: consume %d/%d, %d,%d ptr %d",
- m68k_cycles, sh2_cycles_diff, sh2_cycles_diff / pwm_cycles,
- Pico32x.pwm_p[0], Pico32x.pwm_p[1], pwm_ptr);
+ m68k_cycles, sh2_cycles_diff, sh2_cycles_diff / pwm.cycles,
+ Pico32x.pwm_p[0], Pico32x.pwm_p[1], pwm.ptr);
// this is for recursion from dreq1 writes
- pwm_doing_fifo = 1;
+ pwm.doing_fifo = 1;
- for (; sh2_cycles_diff >= pwm_cycles; sh2_cycles_diff -= pwm_cycles)
+ for (; sh2_cycles_diff >= pwm.cycles; sh2_cycles_diff -= pwm.cycles)
{
if (Pico32x.pwm_p[0] > 0) {
- fifo_l[0] = fifo_l[1];
- fifo_l[1] = fifo_l[2];
- fifo_l[2] = fifo_l[3];
+ mem->pwm_index[0] = (mem->pwm_index[0]+1) % 4;
Pico32x.pwm_p[0]--;
- mem->pwm_current[0] = convert_sample(fifo_l[0]);
- sum += mem->pwm_current[0];
+ pwm.current[0] = convert_sample(fifo_l[mem->pwm_index[0]]);
+ sum |=pwm.current[0];
}
if (Pico32x.pwm_p[1] > 0) {
- fifo_r[0] = fifo_r[1];
- fifo_r[1] = fifo_r[2];
- fifo_r[2] = fifo_r[3];
+ mem->pwm_index[1] = (mem->pwm_index[1]+1) % 4;
Pico32x.pwm_p[1]--;
- mem->pwm_current[1] = convert_sample(fifo_r[0]);
- sum += mem->pwm_current[1];
+ pwm.current[1] = convert_sample(fifo_r[mem->pwm_index[1]]);
+ sum |= pwm.current[1];
}
- mem->pwm[pwm_ptr * 2 ] = mem->pwm_current[0];
- mem->pwm[pwm_ptr * 2 + 1] = mem->pwm_current[1];
- pwm_ptr = (pwm_ptr + 1) & (PWM_BUFF_LEN - 1);
+ mem->pwm[pwm.ptr * 2 ] = pwm.current[0];
+ mem->pwm[pwm.ptr * 2 + 1] = pwm.current[1];
+ pwm.ptr = (pwm.ptr + 1) & (PWM_BUFF_LEN - 1);
if (--Pico32x.pwm_irq_cnt == 0) {
- Pico32x.pwm_irq_cnt = pwm_irq_reload;
+ Pico32x.pwm_irq_cnt = pwm.irq_reload;
do_pwm_irq(sh2, m68k_cycles);
}
}
Pico32x.pwm_cycle_p = m68k_cycles * 3 - sh2_cycles_diff;
- pwm_doing_fifo = 0;
+ pwm.doing_fifo = 0;
if (sum != 0)
- pwm_silent = 0;
+ pwm.silent = 0;
}
static int p32x_pwm_schedule_(SH2 *sh2, unsigned int m68k_now)
{
- unsigned int sh2_now = m68k_now * 3;
+ unsigned int pwm_now = m68k_now * 3;
int cycles_diff_sh2;
- if (pwm_cycles == 0)
+ if (pwm.cycles == 0)
return 0;
- cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p;
- if (cycles_diff_sh2 >= pwm_cycles)
+ cycles_diff_sh2 = pwm_now - Pico32x.pwm_cycle_p;
+ if (cycles_diff_sh2 >= pwm.cycles)
consume_fifo_do(sh2, m68k_now, cycles_diff_sh2);
if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 1))
return 0; // masked by everyone
- cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p;
- return (Pico32x.pwm_irq_cnt * pwm_cycles
+ cycles_diff_sh2 = pwm_now - Pico32x.pwm_cycle_p;
+ return (Pico32x.pwm_irq_cnt * pwm.cycles
- cycles_diff_sh2) / 3 + 1;
}
consume_fifo(sh2, m68k_cycles);
a &= 0x0e;
- switch (a) {
- case 0: // control
- case 2: // cycle
+ switch (a/2) {
+ case 0/2: // control
+ case 2/2: // cycle
d = Pico32x.regs[(0x30 + a) / 2];
break;
- case 4: // L ch
+ case 4/2: // L ch
if (Pico32x.pwm_p[0] == 3)
d |= P32XP_FULL;
else if (Pico32x.pwm_p[0] == 0)
d |= P32XP_EMPTY;
break;
- case 6: // R ch
- case 8: // MONO
+ case 6/2: // R ch
+ case 8/2: // MONO
if (Pico32x.pwm_p[1] == 3)
d |= P32XP_FULL;
else if (Pico32x.pwm_p[1] == 0)
void p32x_pwm_write16(unsigned int a, unsigned int d,
SH2 *sh2, unsigned int m68k_cycles)
{
+ unsigned short *fifo;
+ int idx;
+
elprintf(EL_PWM, "pwm: %u: w16 %02x %04x (p %d %d)",
m68k_cycles, a & 0x0e, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]);
consume_fifo(sh2, m68k_cycles);
a &= 0x0e;
- if (a == 0) { // control
- // avoiding pops..
- if ((Pico32x.regs[0x30 / 2] & 0x0f) == 0)
- Pico32xMem->pwm_fifo[0][0] = Pico32xMem->pwm_fifo[1][0] = 0;
- Pico32x.regs[0x30 / 2] = d;
- p32x_pwm_ctl_changed();
- Pico32x.pwm_irq_cnt = pwm_irq_reload; // ?
- }
- else if (a == 2) { // cycle
- Pico32x.regs[0x32 / 2] = d & 0x0fff;
- p32x_pwm_ctl_changed();
- }
- else if (a <= 8) {
- d = (d - 1) & 0x0fff;
-
- if (a == 4 || a == 8) { // L ch or MONO
- unsigned short *fifo = Pico32xMem->pwm_fifo[0];
- if (Pico32x.pwm_p[0] < 3)
- Pico32x.pwm_p[0]++;
- else {
- fifo[1] = fifo[2];
- fifo[2] = fifo[3];
- }
- fifo[Pico32x.pwm_p[0]] = d;
- }
- if (a == 6 || a == 8) { // R ch or MONO
- unsigned short *fifo = Pico32xMem->pwm_fifo[1];
+ switch (a/2) {
+ case 0/2: // control
+ // avoiding pops..
+ if ((Pico32x.regs[0x30 / 2] & 0x0f) == 0)
+ Pico32xMem->pwm_fifo[0][0] = Pico32xMem->pwm_fifo[1][0] = 0;
+ Pico32x.regs[0x30 / 2] = d;
+ p32x_pwm_ctl_changed();
+ Pico32x.pwm_irq_cnt = pwm.irq_reload; // ?
+ break;
+ case 2/2: // cycle
+ Pico32x.regs[0x32 / 2] = d & 0x0fff;
+ p32x_pwm_ctl_changed();
+ break;
+ case 8/2: // MONO
+ case 6/2: // R ch
+ fifo = Pico32xMem->pwm_fifo[1];
+ idx = Pico32xMem->pwm_index[1];
if (Pico32x.pwm_p[1] < 3)
Pico32x.pwm_p[1]++;
else {
- fifo[1] = fifo[2];
- fifo[2] = fifo[3];
+// fifo[(idx+1) % 4] = fifo[idx];
+ idx = (idx+1) % 4;
+ Pico32xMem->pwm_index[0] = idx;
}
- fifo[Pico32x.pwm_p[1]] = d;
- }
+ fifo[(idx+Pico32x.pwm_p[1]) % 4] = (d - 1) & 0x0fff;
+ if (a != 8) break; // fallthrough if MONO
+ case 4/2: // L ch
+ fifo = Pico32xMem->pwm_fifo[0];
+ idx = Pico32xMem->pwm_index[0];
+ if (Pico32x.pwm_p[0] < 3)
+ Pico32x.pwm_p[0]++;
+ else {
+// fifo[(idx+1) % 4] = fifo[idx];
+ idx = (idx+1) % 4;
+ Pico32xMem->pwm_index[0] = idx;
+ }
+ fifo[(idx+Pico32x.pwm_p[0]) % 4] = (d - 1) & 0x0fff;
+ break;
}
}
xmd = Pico32x.regs[0x30 / 2] & 0x0f;
if (xmd == 0 || xmd == 0x06 || xmd == 0x09 || xmd == 0x0f)
goto out; // invalid?
- if (pwm_silent)
+ if (pwm.silent)
return;
- step = (pwm_ptr << 16) / length;
+ step = (pwm.ptr << 16) / length;
pwmb = Pico32xMem->pwm;
if (stereo)
}
}
- elprintf(EL_PWM, "pwm_update: pwm_ptr %d, len %d, step %04x, done %d",
- pwm_ptr, length, step, (pwmb - Pico32xMem->pwm) / 2);
+ elprintf(EL_PWM, "pwm_update: pwm.ptr %d, len %d, step %04x, done %d",
+ pwm.ptr, length, step, (pwmb - Pico32xMem->pwm) / 2);
out:
- pwm_ptr = 0;
- pwm_silent = Pico32xMem->pwm_current[0] == 0
- && Pico32xMem->pwm_current[1] == 0;
+ pwm.ptr = 0;
+ pwm.silent = pwm.current[0] == 0 && pwm.current[1] == 0;
}
void p32x_pwm_state_loaded(void)
// for old savestates
cycles_diff_sh2 = Pico.t.m68c_cnt * 3 - Pico32x.pwm_cycle_p;
- if (cycles_diff_sh2 >= pwm_cycles || cycles_diff_sh2 < 0) {
- Pico32x.pwm_irq_cnt = pwm_irq_reload;
+ if (cycles_diff_sh2 >= pwm.cycles || cycles_diff_sh2 < 0) {
+ Pico32x.pwm_irq_cnt = pwm.irq_reload;
Pico32x.pwm_cycle_p = Pico.t.m68c_cnt * 3;
p32x_pwm_schedule(Pico.t.m68c_cnt);
}
{
u32 *r = sh2->peri_regs;
u32 old;
+ struct dmac *dmac;
elprintf_sh2(sh2, EL_32XP, "peri w32 [%08x] %08x @%06x",
a, d, sh2_pc(sh2));
else
r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
break;
- }
-
- // perhaps starting a DMA?
- if (a == 0x1b0 || a == 0x18c || a == 0x19c) {
- struct dmac *dmac = (void *)&sh2->peri_regs[0x180 / 4];
- if (a == 0x1b0 && !((old ^ d) & d & DMA_DME))
- return;
- if (!(dmac->dmaor & DMA_DME))
- return;
-
- DRC_SAVE_SR(sh2);
- if ((dmac->chan[0].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
- dmac_trigger(sh2, &dmac->chan[0]);
- if ((dmac->chan[1].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
- dmac_trigger(sh2, &dmac->chan[1]);
- DRC_RESTORE_SR(sh2);
+ // perhaps starting a DMA?
+ case 0x18c:
+ case 0x19c:
+ case 0x1b0:
+ dmac = (void *)&sh2->peri_regs[0x180 / 4];
+ if (a == 0x1b0 && !((old ^ d) & d & DMA_DME))
+ return;
+ if (!(dmac->dmaor & DMA_DME))
+ return;
+
+ DRC_SAVE_SR(sh2);
+ if ((dmac->chan[0].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
+ dmac_trigger(sh2, &dmac->chan[0]);
+ if ((dmac->chan[1].chcr & (DMA_TE|DMA_DE)) == DMA_DE)
+ dmac_trigger(sh2, &dmac->chan[1]);
+ DRC_RESTORE_SR(sh2);
+ break;
}
}
*pd++ = pal[*ps++];\r
*pd++ = pal[*ps++];\r
}\r
-// for (i = 0; i < len; i++)\r
-// pd[i] = pal[ps[i]];\r
#else\r
extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);\r
extern void amips_clut_6bit(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);\r
unsigned short pal[0x100];\r
unsigned short pal_native[0x100]; // converted to native (for renderer)\r
signed short pwm[2*PWM_BUFF_LEN]; // PWM buffer for current frame\r
- signed short pwm_current[2]; // current converted samples\r
unsigned short pwm_fifo[2][4]; // [0] - current raw, others - fifo entries\r
+ unsigned pwm_index[2]; // ringbuffer index for pwm_fifo\r
};\r
\r
// area.c\r