From 7b631dbe47856b35cc9e1a704110a98f37620abc Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 26 Mar 2025 07:23:55 +0100 Subject: [PATCH 01/16] core, make dc filter reacting faster behaves closer to real hw according to measurements by notaz --- pico/sound/mix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pico/sound/mix.c b/pico/sound/mix.c index 1a4785d1..430e6bc7 100644 --- a/pico/sound/mix.c +++ b/pico/sound/mix.c @@ -36,22 +36,22 @@ static struct iir { // exponential moving average combined DC filter and lowpass filter -// y0[n] = (x[n]-y0[n-1])*alpha+y0[n-1], y1[n] = (y0[n] - y1[n-1])*(1-1/8192) +// y0[n] = y0[n-1]+(x[n]-y0[n-1])*alpha, y1[n] = y[n-1]+(y0[n]-y1[n-1])*(1/512) static inline int filter_band(struct iir *fi2, int x) { // low pass. alpha is Q8 to avoid loss by 32 bit overflow. // fi2->y[0] += ((x<<(QB-8)) - (fi2->y[0]>>8)) * fi2->alpha; fi2->y[0] += (x - (fi2->y[0]>>QB)) * fi2->alpha; - // DC filter. for alpha=1-1/8192 cutoff ~1HZ, for 1-1/1024 ~7Hz - fi2->y[1] += (fi2->y[0] - fi2->y[1]) >> QB; + // DC filter. for alpha=1/8192 cutoff ~1HZ, for 1/512 ~14Hz + fi2->y[1] += (fi2->y[0] - fi2->y[1]) >> 9; return (fi2->y[0] - fi2->y[1]) >> QB; } // exponential moving average filter for DC filtering -// y[n] = (x[n]-y[n-1])*(1-1/8192) (corner approx. 1Hz, gain 1) +// y[n]= y[n-1] + (x[n]-y[n-1])*(1/512) (corner approx. 14Hz, gain 1) static inline int filter_exp(struct iir *fi2, int x) { - fi2->y[1] += ((x << QB) - fi2->y[1]) >> QB; + fi2->y[1] += ((x << QB) - fi2->y[1]) >> 9; return x - (fi2->y[1] >> QB); } -- 2.39.5 From 104133eeb4cff907d9aedf4763659252b8c5786f Mon Sep 17 00:00:00 2001 From: kub Date: Fri, 28 Mar 2025 08:41:51 +0100 Subject: [PATCH 02/16] core, make dc filter reacting faster (arm) --- pico/sound/mix_arm.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico/sound/mix_arm.S b/pico/sound/mix_arm.S index 64383c3a..486aa5b5 100644 --- a/pico/sound/mix_arm.S +++ b/pico/sound/mix_arm.S @@ -299,7 +299,7 @@ m16_32_rsm_end: @ in=int_sample (max 20 bit), y=filter memory, r8=tmp .macro DCfilt in y rsb r8, \y, \in, lsl #12 @ fixpoint 20.12 - add \y, \y, r8, asr #12 @ alpha = 1-1/4094 + add \y, \y, r8, asr #9 @ alpha = 1-1/512 sub \in, \in, \y, asr #12 .endm -- 2.39.5 From 4e18e219458050be05161a138edb4c051022c752 Mon Sep 17 00:00:00 2001 From: kub Date: Fri, 28 Mar 2025 08:43:43 +0100 Subject: [PATCH 03/16] mcd, powerup fixes --- pico/cd/cd_image.c | 9 +++++++++ pico/cd/cdd.c | 35 ++++++++++++++++------------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/pico/cd/cd_image.c b/pico/cd/cd_image.c index d2210a6f..582b3e32 100644 --- a/pico/cd/cd_image.c +++ b/pico/cd/cd_image.c @@ -198,6 +198,11 @@ int load_cd_image(const char *cd_img_name, int *type) elprintf(EL_STATUS, "Track %2i: %s %9i %s %s", n, tmp_ext, length, tracks[index].type ? "AUDIO" : "DATA ", cue_data->tracks[n].fname ? cue_data->tracks[n].fname : ""); + + if (tracks[index].end > 99*60*75-151) { + tracks[index].end = 99*60*75-151; + break; + } } goto finish; } @@ -263,6 +268,10 @@ int load_cd_image(const char *cd_img_name, int *type) } if (ret <= 0 && i > 1) missed++; + else if (tracks[index].end > 99*60*75-151) { + tracks[index].end = 99*60*75-151; + break; + } } finish: diff --git a/pico/cd/cdd.c b/pico/cd/cdd.c index a1ee9cd2..a06568bf 100644 --- a/pico/cd/cdd.c +++ b/pico/cd/cdd.c @@ -195,9 +195,11 @@ void cdd_play_audio(int index, int lba) for (i = index; i >= 0; i--) if (cdd.toc.tracks[i].fd != NULL) break; + // prevent playing from file with binary track if MD+ (Doom Fusion) // TODO: this doesn't cover all tracks being in a single bin file properly: // in that case, fd should be duplicated to work properly with this MD+ shit. - if (! is_audio(i)) return; + if (! is_audio(index) || (read_pos >= 0 && cdd.index == i && ! is_audio(i))) + return; Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd; Pico_mcd->cdda_type = cdd.toc.tracks[i].type; @@ -210,33 +212,28 @@ void cdd_play_audio(int index, int lba) cdda_start_play(base, lba_offset, lb_len); } -void cdd_seek(int index, int lba) +static void cdd_seek(int index, int lba) { - int aindex = (index < 0 ? -index : index); - #ifdef USE_LIBTREMOR #ifdef DISABLE_MANY_OGG_OPEN_FILES - /* check if track index has changed */ - if (index != cdd.index) + /* close previous track VORBIS file structure to save memory */ + if (is_audio(cdd.index) && cdd.toc.tracks[cdd.index].vf.datasource) { - /* close previous track VORBIS file structure to save memory */ - if (cdd.index >= 0 && cdd.toc.tracks[cdd.index].vf.datasource) - { - ogg_free(cdd.index); - } + ogg_free(cdd.index); + } - /* open current track VORBIS file */ - if (cdd.toc.tracks[aindex].vf.seekable) - { - ov_open(cdd.toc.tracks[aindex].fd,&cdd.toc.tracks[aindex].vf,0,0); - } + /* open current track VORBIS file */ + if (is_audio(index) && cdd.toc.tracks[index].vf.seekable) + { + ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0); } #endif #endif /* update current track index and LBA */ - cdd.index = aindex; + cdd.index = (index < 0 ? 0 : index); cdd.lba = lba; + if (index < 0) return; /* stay within track limits when seeking files */ if (lba < cdd.toc.tracks[cdd.index].start) @@ -300,7 +297,7 @@ int cdd_context_load(uint8 *state) load_param(&cdd.status, sizeof(cdd.status)); /* seek to current track position */ - cdd_seek(-cdd.index, cdd.lba); + cdd_seek(cdd.index, cdd.lba); return bufferptr; } @@ -308,7 +305,7 @@ int cdd_context_load(uint8 *state) int cdd_context_load_old(uint8 *state) { memcpy(&cdd.lba, state + 8, sizeof(cdd.lba)); - cdd_seek(-cdd.index, cdd.lba); + cdd_seek(cdd.index, cdd.lba); return 12 * 4; } -- 2.39.5 From 588881c4f8b8bbd6e91122dd660bcfacbd3a6296 Mon Sep 17 00:00:00 2001 From: kub Date: Fri, 28 Mar 2025 09:27:28 +0100 Subject: [PATCH 04/16] mcd, improve cdda save state --- pico/cd/mcd.c | 22 ++++++++++++++++++++-- pico/cd/megasd.c | 1 + pico/pico_int.h | 8 +++++--- pico/sound/sound.c | 30 +++++++++++++++++++++--------- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/pico/cd/mcd.c b/pico/cd/mcd.c index 42a5a515..9476f501 100644 --- a/pico/cd/mcd.c +++ b/pico/cd/mcd.c @@ -151,10 +151,10 @@ static void SekRunS68k(unsigned int to) void PicoMCDPrepare(void) { - // ~1.63 for NTSC, ~1.645 for PAL + // 12500000/(osc/7), ~1.63 for NTSC, ~1.645 for PAL #define DIV_ROUND(x,y) ((x)+(y)/2) / (y) // round to nearest, x/y+0.5 -> (x+y/2)/y unsigned int osc = (Pico.m.pal ? OSC_PAL : OSC_NTSC); - mcd_m68k_cycle_mult = DIV_ROUND(12500000ull << 16, osc / 7); + mcd_m68k_cycle_mult = DIV_ROUND(7 * 12500000ull << 16, osc); mcd_s68k_cycle_mult = DIV_ROUND(1ull * osc << 16, 7 * 12500000); } @@ -166,9 +166,27 @@ unsigned int pcd_cycles_m68k_to_s68k(unsigned int c) /* events */ static void pcd_cdc_event(unsigned int now) { + int audio = Pico_mcd->s68k_regs[0x36] & 0x1; + // 75Hz CDC update cdd_update(); + // main 68k cycles since frame start + int cycles = 1LL*(now-mcd_s68k_cycle_base) * mcd_s68k_cycle_mult >> 16; + // samples@rate since frame start + int samples = 1LL * cycles_68k_to_z80(cycles) * Pico.snd.clkz_mult >> 20; + // samples@44100Hz since frame start + samples = samples * Pico.snd.cdda_mult >> 16; + if (samples < 2352/4) // save offset to 1st used sample for state saving + Pico_mcd->m.cdda_lba_offset = 2352/4 - samples; + + /* if audio just turned on, store start offset for sound */ + audio &= !(Pico_mcd->s68k_regs[0x36] & 0x1); + if (audio) { + Pico_mcd->m.cdda_lba_offset = 0; // starting with full lba + Pico_mcd->cdda_frame_offs = samples; + } + /* check if a new CDD command has been processed */ if (!(Pico_mcd->s68k_regs[0x4b] & 0xf0)) { diff --git a/pico/cd/megasd.c b/pico/cd/megasd.c index bc03d17c..4a8f42c3 100644 --- a/pico/cd/megasd.c +++ b/pico/cd/megasd.c @@ -46,6 +46,7 @@ static void cdd_play(s32 lba) { Pico_msd.currentlba = lba; + Pico_mcd->m.cdda_lba_offset = 0; cdd_play_audio(Pico_msd.index, Pico_msd.currentlba); Pico_msd.state |= MSD_ST_PLAY; Pico_msd.state &= ~MSD_ST_PAUSE; diff --git a/pico/pico_int.h b/pico/pico_int.h index c98a02a6..e2fd39ab 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -270,7 +270,7 @@ extern SH2 sh2s[2]; // --------------------------------------------------------- // main oscillator clock which controls timing -#define OSC_NTSC 53693100 +#define OSC_NTSC 53693175 #define OSC_PAL 53203424 // PicoVideo.debug_p @@ -475,7 +475,7 @@ struct PicoSound short len_use; // adjusted int len_e_add; // for non-int samples/frame int len_e_cnt; - unsigned int clkl_mult; // z80 clocks per line in Q20 + unsigned int clkz_mult; // z80 clocks per sample in Q20 unsigned int smpl_mult; // samples per line in Q16 unsigned int cdda_mult, cdda_div; // 44.1 KHz resampling factor in Q16 short dac_val, dac_val2; // last DAC sample @@ -547,7 +547,8 @@ struct mcd_misc unsigned char need_sync; unsigned char pad3; unsigned int m68k_poll_clk; - int pad4[8]; + unsigned int cdda_lba_offset; // 20 + int pad4[7]; }; typedef struct @@ -577,6 +578,7 @@ typedef struct struct mcd_pcm pcm; // 112240: void *cdda_stream; int cdda_type; + unsigned int cdda_frame_offs; int pcm_mixbuf[PCM_MIXBUF_LEN * 2]; int pcm_mixpos; char pcm_mixbuf_dirty; diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 26a182f8..455aac7b 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -189,8 +189,8 @@ void PsndRerate(int preserve_state) // samples per line (Q16) Pico.snd.smpl_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines); // samples per z80 clock (Q20) - Pico.snd.clkl_mult = 16 * Pico.snd.smpl_mult * 15/7 / 488.5; - // samples per 44.1 KHz sample + Pico.snd.clkz_mult = 16 * Pico.snd.smpl_mult * 15/7 / 488.5; + // samples per 44.1 KHz sample (Q16) Pico.snd.cdda_mult = 65536LL * 44100 / PicoIn.sndRate; Pico.snd.cdda_div = 65536LL * PicoIn.sndRate / 44100; @@ -229,7 +229,7 @@ PICO_INTERNAL void PsndDoDAC(int cyc_to) if (!PicoIn.sndOut) return; // number of samples to fill in buffer (Q20) - len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.dac_pos; + len = (cyc_to * Pico.snd.clkz_mult) - Pico.snd.dac_pos; // update position and calculate buffer offset and length pos = (Pico.snd.dac_pos+0x80000) >> 20; @@ -271,7 +271,7 @@ PICO_INTERNAL void PsndDoPSG(int cyc_to) if (!PicoIn.sndOut) return; // number of samples to fill in buffer (Q20) - len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.psg_pos; + len = (cyc_to * Pico.snd.clkz_mult) - Pico.snd.psg_pos; // update position and calculate buffer offset and length pos = (Pico.snd.psg_pos+0x80000) >> 20; @@ -301,7 +301,7 @@ PICO_INTERNAL void PsndDoSMSFM(int cyc_to) if (!PicoIn.sndOut) return; // number of samples to fill in buffer (Q20) - len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.ym2413_pos; + len = (cyc_to * Pico.snd.clkz_mult) - Pico.snd.ym2413_pos; // update position and calculate buffer offset and length pos = (Pico.snd.ym2413_pos+0x80000) >> 20; @@ -342,7 +342,7 @@ PICO_INTERNAL void PsndDoFM(int cyc_to) if (!PicoIn.sndOut) return; // Q20, number of samples since last call - len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.fm_pos; + len = (cyc_to * Pico.snd.clkz_mult) - Pico.snd.fm_pos; // update position and calculate buffer offset and length pos = (Pico.snd.fm_pos+0x80000) >> 20; @@ -369,7 +369,7 @@ PICO_INTERNAL void PsndDoPCM(int cyc_to) if (!PicoIn.sndOut) return; // Q20, number of samples since last call - len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.pcm_pos; + len = (cyc_to * Pico.snd.clkz_mult) - Pico.snd.pcm_pos; // update position and calculate buffer offset and length pos = (Pico.snd.pcm_pos+0x80000) >> 20; @@ -391,13 +391,23 @@ static void cdda_raw_update(s32 *buffer, int length, int stereo) { int ret, cdda_bytes; + // apply start offset in frame (offset to 1st lba to play) + int offs = Pico_mcd->cdda_frame_offs * Pico.snd.cdda_div >> 16; + length -= offs; + buffer += offs * (stereo ? 2 : 1); + Pico_mcd->cdda_frame_offs = 0; + cdda_bytes = (length * Pico.snd.cdda_mult >> 16) * 4; + // compute offset of last played sample in this frame (need for save/load) + Pico_mcd->m.cdda_lba_offset += cdda_bytes/4; + while (Pico_mcd->m.cdda_lba_offset >= 2352/4) + Pico_mcd->m.cdda_lba_offset -= 2352/4; + ret = pm_read_audio(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream); if (ret < cdda_bytes) { memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret); Pico_mcd->cdda_stream = NULL; - return; } // now mix @@ -423,7 +433,9 @@ void cdda_start_play(int lba_base, int lba_offset, int lb_len) return; } - pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET); + // on restart after loading, consider offset of last played sample + pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352 + + Pico_mcd->m.cdda_lba_offset * 4, SEEK_SET); if (Pico_mcd->cdda_type == CT_WAV) { // skip headers, assume it's 44kHz stereo uncompressed -- 2.39.5 From e6bb77d1a1770882dbae14dce70fa9d4de19b0f7 Mon Sep 17 00:00:00 2001 From: kub Date: Fri, 28 Mar 2025 23:02:40 +0100 Subject: [PATCH 05/16] mcd, improve pcm save state --- pico/cd/mcd.c | 6 ++---- pico/cd/pcm.c | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pico/cd/mcd.c b/pico/cd/mcd.c index 9476f501..4140f20a 100644 --- a/pico/cd/mcd.c +++ b/pico/cd/mcd.c @@ -442,7 +442,6 @@ PICO_INTERNAL void PicoFrameMCD(void) void pcd_state_loaded(void) { unsigned int cycles; - int diff; pcd_state_loaded_mem(); @@ -453,7 +452,7 @@ void pcd_state_loaded(void) // old savestates.. cycles = pcd_cycles_m68k_to_s68k(Pico.t.m68c_aim); - if (CYCLES_GE(cycles - SekCycleAimS68k, 1000)) { + if (CYCLES_GE(cycles - SekCycleAimS68k, 12500000/60)) { SekCycleCntS68k = SekCycleAimS68k = cycles; } if (pcd_event_times[PCD_EVENT_CDC] == 0) { @@ -464,8 +463,7 @@ void pcd_state_loaded(void) (Pico_mcd->s68k_regs[0x31]+1) * 384); } - diff = cycles - Pico_mcd->pcm.update_cycles; - if ((unsigned int)diff > 12500000/50) + if (CYCLES_GE(cycles - Pico_mcd->pcm.update_cycles, 12500000/50)) Pico_mcd->pcm.update_cycles = cycles; if (Pico_mcd->m.need_sync) { diff --git a/pico/cd/pcm.c b/pico/cd/pcm.c index b38ce2d6..abb65f6c 100644 --- a/pico/cd/pcm.c +++ b/pico/cd/pcm.c @@ -62,7 +62,7 @@ void pcd_pcm_sync(unsigned int to) if ((int)(to - cycles) < 384) return; - steps = (to - cycles) / 384; + steps = (to - cycles) * ((1LL << 32) / 384) >> 32; if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN) // shouldn't happen, but occasionally does steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos; @@ -147,7 +147,7 @@ void pcd_pcm_update(s32 *buf32, int length, int stereo) else { while (length-- > 0) { // mostly unused - *buf32++ += pcm[0]; + *buf32++ += (pcm[0] + pcm[1]) >> 1; p += step; pcm += (p >> 16) * 2; -- 2.39.5 From eb6affd5cff297f5093279c8fa283feeaf694181 Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 29 Mar 2025 17:06:28 +0000 Subject: [PATCH 06/16] mcd, fix 32x regression --- pico/cd/gfx.c | 2 ++ pico/media.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pico/cd/gfx.c b/pico/cd/gfx.c index 4df1c34f..50338827 100644 --- a/pico/cd/gfx.c +++ b/pico/cd/gfx.c @@ -148,6 +148,7 @@ int gfx_context_save(uint8 *state) save_param(&tmp32, 4); save_param(&gfx.y_step, sizeof(gfx.y_step)); + save_param(&gfx.stampMask, sizeof(gfx.stampMask)); return bufferptr; } @@ -172,6 +173,7 @@ int gfx_context_load(const uint8 *state) gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32); load_param(&gfx.y_step, sizeof(gfx.y_step)); + load_param(&gfx.stampMask, sizeof(gfx.stampMask)); return bufferptr; } diff --git a/pico/media.c b/pico/media.c index e0c25b24..ff7a338a 100644 --- a/pico/media.c +++ b/pico/media.c @@ -412,6 +412,12 @@ enum media_type_e PicoLoadMedia(const char *filename, lprintf("detected SMS ROM\n"); } + if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname)) { + media_type = PM_ERROR; + goto out; + } + rom_data = NULL; // now belongs to PicoCart + // insert CD if it was detected Pico.m.ncart_in = 0; if (cd_img_type != CT_UNKNOWN) { @@ -425,12 +431,6 @@ enum media_type_e PicoLoadMedia(const char *filename, Pico.m.ncart_in = 1; } - if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname)) { - media_type = PM_ERROR; - goto out; - } - rom_data = NULL; // now belongs to PicoCart - if (PicoIn.quirks & PQUIRK_FORCE_6BTN) PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN); -- 2.39.5 From 86dceea126da3bb084b19dbdd71fa97b930c91fd Mon Sep 17 00:00:00 2001 From: kub Date: Sat, 29 Mar 2025 21:38:16 +0100 Subject: [PATCH 07/16] 32x, add timer to save state --- pico/32x/sh2soc.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/pico/32x/sh2soc.c b/pico/32x/sh2soc.c index 7d1e0d45..bc0db3eb 100644 --- a/pico/32x/sh2soc.c +++ b/pico/32x/sh2soc.c @@ -189,15 +189,13 @@ static void dmac_trigger(SH2 *sh2, struct dma_chan *chan) chan->sar, chan->dar, chan->tcr, chan->chcr, sh2->pc); } -// timer state - FIXME -static u32 timer_cycles[2]; // TODO save this in state! -static u32 timer_tick_cycles[2]; -static u32 timer_tick_factor[2]; +// FIXME, timer state, in unused peri_regs space to have it in state save/load +#define timer_cycles(sh2) *((u32 *)&(sh2)->peri_regs[0x1c]) +static u32 timer_tick_shift[2]; // timers void p32x_timers_recalc(void) { - int cycles; int tmp, i; // SH2 timer step @@ -210,11 +208,8 @@ void p32x_timers_recalc(void) if (tmp >= 6) tmp++; if (tmp) tmp += 5; else tmp = 1; - cycles = 1 << tmp; - timer_tick_cycles[i] = cycles; - timer_tick_factor[i] = tmp; - timer_cycles[i] = 0; - elprintf(EL_32XP, "WDT cycles[%d] = %d", i, cycles); + timer_tick_shift[i] = tmp; + elprintf(EL_32XP, "WDT cycles[%d] = %d", i, 1 << tmp); } } @@ -225,10 +220,10 @@ NOINLINE void p32x_timer_do(SH2 *sh2, unsigned int m68k_slice) int cnt; int i = sh2->is_slave; // WDT timer - timer_cycles[i] += cycles; - if (timer_cycles[i] > timer_tick_cycles[i]) { - cnt = (timer_cycles[i] >> timer_tick_factor[i]); - timer_cycles[i] -= timer_tick_cycles[i] * cnt; + timer_cycles(sh2) += cycles; + cnt = (timer_cycles(sh2) >> timer_tick_shift[i]); + if (cnt) { + timer_cycles(sh2) -= cnt << timer_tick_shift[i]; cnt += PREG8(pregs, 0x81); if (cnt >= 0x100) { @@ -411,6 +406,7 @@ void REGPARM(3) sh2_peripheral_write16(u32 a, u32 d, SH2 *sh2) if ((d & 0xff00) == 0xa500) { // WTCSR PREG8(r, 0x80) = d; p32x_timers_recalc(); + timer_cycles(sh2) = 0; } if ((d & 0xff00) == 0x5a00) // WTCNT PREG8(r, 0x81) = d; -- 2.39.5 From 5180232e0fd1a12590fe3543ab36be589a186769 Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 30 Mar 2025 19:11:01 +0200 Subject: [PATCH 08/16] core md, add interlace field info to video status --- pico/pico.c | 2 -- pico/pico_cmn.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pico/pico.c b/pico/pico.c index ee3d1438..e305e3b1 100644 --- a/pico/pico.c +++ b/pico/pico.c @@ -297,8 +297,6 @@ void PicoFrame(void) goto end; } - //if(Pico.video.reg[12]&0x2) Pico.video.status ^= SR_ODD; // change odd bit in interlace mode - PicoFrameStart(); PicoFrameHints(); diff --git a/pico/pico_cmn.c b/pico/pico_cmn.c index 39a3d158..37198f11 100644 --- a/pico/pico_cmn.c +++ b/pico/pico_cmn.c @@ -231,6 +231,11 @@ static int PicoFrameHints(void) p32x_start_blank(); #endif + if (pv->reg[12] & 2) + pv->status ^= SR_ODD; // change odd bit in interlace modes + else + pv->status &= ~SR_ODD; // never set in non-interlace modes + // the following SekRun is there for several reasons: // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga) // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants) -- 2.39.5 From a280872d7706f40f5c1e677ed2af2b2865f880e0 Mon Sep 17 00:00:00 2001 From: kub Date: Mon, 31 Mar 2025 20:41:59 +0200 Subject: [PATCH 09/16] platform ps2, improve pad detection --- platform/libpicofe | 2 +- platform/ps2/in_ps2.c | 54 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/platform/libpicofe b/platform/libpicofe index ce684c88..c3031dbf 160000 --- a/platform/libpicofe +++ b/platform/libpicofe @@ -1 +1 @@ -Subproject commit ce684c885ecafe0b9279a6c54b97f96e84ece6d3 +Subproject commit c3031dbfda557f7058756583b329b59ea92a72dc diff --git a/platform/ps2/in_ps2.c b/platform/ps2/in_ps2.c index 5ddf0e9a..7a7817c5 100644 --- a/platform/ps2/in_ps2.c +++ b/platform/ps2/in_ps2.c @@ -21,7 +21,8 @@ #define IN_PS2_PREFIX "ps2:" #define IN_PS2_NBUTTONS 32 -#define ANALOG_DEADZONE 80 + +struct in_default_bind *in_ps2_defbinds[4]; /* note: in_ps2 handles combos (if 2 btns have the same bind, * both must be pressed for action to happen) */ @@ -82,14 +83,16 @@ static unsigned in_ps2_get_bits(int pad) static void in_ps2_probe(const in_drv_t *drv) { - in_register(IN_PS2_PREFIX "PS2 pad 1", -1, (void *)0, - IN_PS2_NBUTTONS, in_ps2_keys, 1); - in_register(IN_PS2_PREFIX "PS2 pad 2", -1, (void *)1, - IN_PS2_NBUTTONS, in_ps2_keys, 1); - in_register(IN_PS2_PREFIX "PS2 pad 3", -1, (void *)2, - IN_PS2_NBUTTONS, in_ps2_keys, 1); - in_register(IN_PS2_PREFIX "PS2 pad 4", -1, (void *)3, - IN_PS2_NBUTTONS, in_ps2_keys, 1); + char *name = IN_PS2_PREFIX "PS2 pad 0/0"; + int num = (int)drv->pdata; + int offs = strlen(name)-3; + + name[offs] = '1'+padMap[num][0]; + if (mtapGetConnection(padMap[num][0]) == 1) + name[offs+2] = '1'+padMap[num][1]; + else name[offs+1] = '\0'; + if (num < padMapped) + in_register(name, -1, (void *)num, IN_PS2_NBUTTONS, in_ps2_keys, 1); } static void in_ps2_free(void *drv_data) @@ -226,6 +229,20 @@ static const in_drv_t in_ps2_drv = { .menu_translate = in_ps2_menu_translate, }; +static struct in_default_bind *copy_defbinds(struct in_default_bind *defbinds) +{ + struct in_default_bind *newbinds; + int count = 0; + + while (defbinds[count].code| defbinds[count].btype| defbinds[count].bit) + count ++; + + newbinds = malloc((count+1) * sizeof(*defbinds)); + if (newbinds) + memcpy(newbinds, defbinds, (count+1) * sizeof(*defbinds)); + return newbinds; +} + void in_ps2_init(struct in_default_bind *defbinds) { int i, j; @@ -278,6 +295,23 @@ void in_ps2_init(struct in_default_bind *defbinds) in_ps2_keys[lg2(PAD_CROSS)] = "Cross"; in_ps2_keys[lg2(PAD_SQUARE)] = "Square"; - in_register_driver(&in_ps2_drv, defbinds, NULL, NULL); + /* copy default binds and map the 4 controllers to 4 players */ + for (i = 0; i < 4; i++) { + in_ps2_defbinds[i] = copy_defbinds(defbinds); + for (j = 0; in_ps2_defbinds[i]; j++) { + struct in_default_bind *p = &in_ps2_defbinds[i][j]; + if ((p->code | p->btype | p->bit) == 0) break; + + if (p->btype == IN_BINDTYPE_PLAYER12) { + p->btype += (i >= 2); + p->bit += (i&1) * 16; + } + } + } + + in_register_driver(&in_ps2_drv, in_ps2_defbinds[0], NULL, (void *)0); + in_register_driver(&in_ps2_drv, in_ps2_defbinds[1], NULL, (void *)1); + in_register_driver(&in_ps2_drv, in_ps2_defbinds[2], NULL, (void *)2); + in_register_driver(&in_ps2_drv, in_ps2_defbinds[3], NULL, (void *)3); } -- 2.39.5 From f4906a00f5742c7810c1a2f37739f8fe8edeb605 Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 1 Apr 2025 01:15:21 +0300 Subject: [PATCH 10/16] pandora: don't strip the binary we never did until dab0c3631 --- platform/pandora/Makefile | 5 +---- platform/pandora/PicoDrive.sh | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/platform/pandora/Makefile b/platform/pandora/Makefile index 0eb65193..fee9df86 100644 --- a/platform/pandora/Makefile +++ b/platform/pandora/Makefile @@ -23,10 +23,7 @@ all: rel /tmp/PicoDrive.pxml: PicoDrive.pxml.template FORCE ./make_pxml.sh $< $@ -PicoDrive: ../../picodrive - $(STRIP) $^ -o $@ - -rel: PicoDrive PicoDrive.sh picorestore \ +rel: ../../picodrive PicoDrive.sh picorestore \ PicoDrive.png PicoDrive_p.png \ ../../pico/carthw.cfg skin \ ../../README.md /tmp/PicoDrive.pxml diff --git a/platform/pandora/PicoDrive.sh b/platform/pandora/PicoDrive.sh index 729a7c19..2193b81a 100755 --- a/platform/pandora/PicoDrive.sh +++ b/platform/pandora/PicoDrive.sh @@ -6,7 +6,7 @@ if [ "`uname -r`" != "3.2.30" ]; then sudo -n /usr/pandora/scripts/op_hugetlb.sh 4 fi -./PicoDrive "$@" +./picodrive "$@" # restore stuff if pico crashes ./picorestore -- 2.39.5 From 7217042b2ba9797f7c69c961a8f023a8d9d0b856 Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 30 Mar 2025 23:30:42 +0200 Subject: [PATCH 11/16] update readme files --- README.md | 14 ++++++++--- platform/base_readme.txt | 50 +++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 7d15497c..3b2f40ab 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,16 @@ Further instructions can be found in `platform/base_readme.txt`. PicoDrive can use Storyware pages and pad overlays in png format in the same directory as the cartridge image. The selected page is displayed automatically if the pen is used on the storyware or pad. Details about how to correctly name -the pages can be found in the *How to run Sega Pico games* section in -`platform/base_readme.txt`. +the pages can be found in `platform/base_readme.txt`. + +### Sega Pico Pen and Sega Mouse + +On all platforms with physical mouse support, PicoDrive can use real mouse +input to emulate a Sega Mouse or the Pico Pen. A physical mouse can be operated +in either a captured or uncaptured state, selectable via the `Capture mouse` hotkey. +Mouse mode can be activated by setting `mouse` as the input device for one +of the pads. It depends on the game as to which pad should be used for mouse +input. More information is located in `platform/base_readme.txt`. ### Sega Pico and SC-3000 Keyboards @@ -42,7 +50,7 @@ Both physical keyboard support and a virtual keyboard overlay are available. Physical keyboards are assigned a default key mapping corresponding to an American PC layout, but the mapping can be redefined in the `Controls` configuration menu. Note that only 'unmodified' physical key presses (e.g. -`A`, `1` etc) can be mapped to emulated keyboard input; special characters +`a`, `1` etc) can be mapped to emulated keyboard input; special characters entered via modifier/meta keys (e.g. `Ctrl`, `Shift` etc) will not work. Additional information may be found in `platform/base_readme.txt`. diff --git a/platform/base_readme.txt b/platform/base_readme.txt index cd5030e7..69424c42 100644 --- a/platform/base_readme.txt +++ b/platform/base_readme.txt @@ -95,23 +95,34 @@ scaled to fit the screen. There are 2 menu actions for switching to pages or pad which will automatically display the images if they are available. To allow for proper pen positioning -there is also an action for having the pen on the page/touchpad or not. Pen -positioning is done through the D-pad if the screen has been switched to either -pages or pad. +there is also a function for having the pen on the page/touchpad or not, the +toggle for which is mapped to the START pad button. Pen positioning is done +through the D-pad if the screen has been switched to either pages or pad, or by +mouse if physical mouse support is activated. -How to load SC-3000 tapes -------------------------- +How to use the mouse +-------------------- + +If the host system has physical mouse support, PicoDrive can use real mouse +input to emulate a Sega Mouse on a MegaDrive base, or to control the Pico Pen. +To activate this functionality, select `mouse` as the input device for one of +the pads. It depends on the game as to which pad should be used for mouse +input. +For Pico games, one input device should be set to `pad`, the other to `mouse`. -The SC-3000 microcomputer has a connector for connecting a cassette tape drive -to it. PicoDrive supports using tape recordings in WAV or bitstream format. -Run one of the BASIC cartridges, then load the tape with the "Load tape" menu. -Entering the LOAD command using the keyboard emulation automatically starts -the emulated tape drive. You will get a confirmation after the tape has been -loaded. +A physical mouse can be operated in either a captured or uncaptured state, +selectable via the `Capture mouse` hotkey. In captured mode, mouse movements +for the whole screen are sent to PicoDrive; in uncaptured mode, only mouse +movements inside the PicoDrive window are tracked. -The emulated tape drive has an automatic start/stop feature. Tapes requiring -several load operations don't need any additional handling. +The physical mouse buttons are mapped as follows: + +| Physical Mouse | Sega Mouse | Pico Pen | +|:--------------:|:----------:|:-----------:| +| Left Button | B | Pen Button | +| Middle Button | START | Red Button | +| Right Button | C | Pen Up/Down | How to use keyboard input @@ -139,6 +150,19 @@ on the state the color of the key changes slightly. Only one meta key can be active at the same time. +How to load SC-3000 tapes +------------------------- + +The SC-3000 microcomputer has a connector for attaching a cassette tape drive. +PicoDrive supports tape recordings in WAV or bitstream format. Run one of the +BASIC cartridges then load the tape image via the `Load tape` menu. Entering +the `LOAD` command using the emulated keyboard automatically starts the virtual +tape drive. Confirmation will usually be provided after the tape has been read. + +The virtual tape drive has an automatic start/stop feature. Tapes requiring +several load operations are handled without the need for user intervention. + + Other important stuff --------------------- -- 2.39.5 From 06ad4337d5b97850209d23d8bf2540dd664f6351 Mon Sep 17 00:00:00 2001 From: kub Date: Tue, 1 Apr 2025 21:09:40 +0200 Subject: [PATCH 12/16] core md, set interlace odd field flag at proper cycle --- pico/pico_cmn.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pico/pico_cmn.c b/pico/pico_cmn.c index 37198f11..00785223 100644 --- a/pico/pico_cmn.c +++ b/pico/pico_cmn.c @@ -231,11 +231,6 @@ static int PicoFrameHints(void) p32x_start_blank(); #endif - if (pv->reg[12] & 2) - pv->status ^= SR_ODD; // change odd bit in interlace modes - else - pv->status &= ~SR_ODD; // never set in non-interlace modes - // the following SekRun is there for several reasons: // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga) // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants) @@ -247,6 +242,7 @@ static int PicoFrameHints(void) SyncCPUs(Pico.t.m68c_aim); + // slot 0x00 pv->status |= SR_F; pv->pending_ints |= 0x20; @@ -262,6 +258,12 @@ static int PicoFrameHints(void) SekInterrupt(6); } + // slot 0x01 + if (pv->reg[12] & 2) + pv->status ^= SR_ODD; // change odd bit in interlace modes + else + pv->status &= ~SR_ODD; // never set in non-interlace modes + // assert Z80 interrupt for one scanline even in busrq hold (Teddy Blues) if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) { elprintf(EL_INTS, "zint"); -- 2.39.5 From 7fefaef4bf446142fedc8c3c22419817b4b5ab78 Mon Sep 17 00:00:00 2001 From: kub Date: Tue, 1 Apr 2025 21:09:56 +0200 Subject: [PATCH 13/16] release 2.04 --- platform/common/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/common/version.h b/platform/common/version.h index d7f2cba3..3810ddd1 100644 --- a/platform/common/version.h +++ b/platform/common/version.h @@ -1 +1 @@ -#define VERSION "2.03" REVISION +#define VERSION "2.04" REVISION -- 2.39.5 From b8a54c7a6f9086f2e98f79d1834a5130e414f931 Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 3 Apr 2025 21:08:07 +0200 Subject: [PATCH 14/16] core, fix interlace in arm assembly --- pico/draw_arm.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pico/draw_arm.S b/pico/draw_arm.S index d3f456ed..73ee07f7 100644 --- a/pico/draw_arm.S +++ b/pico/draw_arm.S @@ -836,7 +836,9 @@ DrawLayer: mov r0, sp mov r1, r9, lsr #29 - bl DrawStripInterlace @ struct TileStrip *ts, int plane_sh + mov r2, r9, lsr #8 + and r2, r2, #0xff + bl DrawStripInterlace @ struct TileStrip *ts, int plane_sh, int cellskip add sp, sp, #6*4 ldmfd sp!, {r4-r11,pc} -- 2.39.5 From 634347ba6200023d3365793ce951aff482a36564 Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 3 Apr 2025 21:08:23 +0200 Subject: [PATCH 15/16] core, another layer A window rendering fix --- pico/draw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pico/draw.c b/pico/draw.c index 2d47998c..48cc8b8e 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -600,7 +600,7 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, struct PicoVideo *pvid = &est->Pico->video; int tilex,ty,nametab,code,oldcode=-1,blank=-1; // The tile we know is blank int yshift,ymask; - u32 pack=0; + u32 pack=0, pal=0; u32 *hc=NULL, lflags=0; // referenced in DrawTile yshift = 4, ymask = 0x7; @@ -634,7 +634,7 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, sh = (sh ? 0x80 : 0x00); // sh and low prio -> shadow for (; tilex < tend; tilex++) { - int dx, pal=0; + int dx; code = PicoMem.vram[nametab + tilex]; if ((code>>15) != prio) { @@ -652,7 +652,7 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, sh = lflags; // sh and high prio -> no shadow (lflags to suppress warning) for (; tilex < tend; tilex++) { - int dx, pal=0; + int dx; code = PicoMem.vram[nametab + tilex]; if((code>>15) != prio) { -- 2.39.5 From 26ecb2b6358fefba24e3d68b9eb2efba7f10d5ee Mon Sep 17 00:00:00 2001 From: notaz Date: Thu, 3 Apr 2025 02:33:00 +0300 Subject: [PATCH 16/16] pandora: fix readme and pxml version --- platform/pandora/Makefile | 1 + platform/pandora/make_pxml.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/pandora/Makefile b/platform/pandora/Makefile index fee9df86..8a534104 100644 --- a/platform/pandora/Makefile +++ b/platform/pandora/Makefile @@ -30,6 +30,7 @@ rel: ../../picodrive PicoDrive.sh picorestore \ rm -rf out mkdir out cp -r $^ out/ + mv out/README.md out/README $(PND_MAKE) -p PicoDrive_$(VER).pnd -d out -x out/PicoDrive.pxml -i out/PicoDrive.png -c FORCE: diff --git a/platform/pandora/make_pxml.sh b/platform/pandora/make_pxml.sh index 35d537a4..1b045459 100755 --- a/platform/pandora/make_pxml.sh +++ b/platform/pandora/make_pxml.sh @@ -7,7 +7,7 @@ test -f $verfile major=`head -n 1 $verfile | sed 's/[^0-9]*\([0-9]*\)\.\([0-9]*\).*/\1/g'` minor=`head -n 1 $verfile | sed 's/[^0-9]*\([0-9]*\)\.\([0-9]*\).*/\2/g'` # lame, I know.. -build=`git describe HEAD | grep -- - | sed -e 's/.*\-\(.*\)\-.*/\1/'` +build=`git describe --tags HEAD | grep -- - | sed -e 's/.*\-\(.*\)\-.*/\1/'` test -n "$build" && build_post="-$build" test -n "$build" || build=0 -- 2.39.5