From 79acacb3ec462848292d96dcc24d588dbabca401 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 10 Jul 2014 17:16:41 +0300 Subject: [PATCH] CD32 FMV cartridge --- ar.cpp | 2 + cd32_fmv.cpp | 1549 ++++++++++++++++++++++++++++++++++++------ cd32_fmv_genlock.cpp | 110 +++ cfgfile.cpp | 27 +- custom.cpp | 33 +- drawing.cpp | 34 +- expansion.cpp | 14 +- include/cd32_fmv.h | 13 + include/custom.h | 1 + include/options.h | 3 +- main.cpp | 14 +- od-win32/mman.cpp | 10 +- 12 files changed, 1563 insertions(+), 247 deletions(-) create mode 100644 cd32_fmv_genlock.cpp diff --git a/ar.cpp b/ar.cpp index 53fbf162..8fe0f15a 100644 --- a/ar.cpp +++ b/ar.cpp @@ -1643,6 +1643,8 @@ int action_replay_load (void) if (_tcslen (currprefs.cartfile) == 0) return 0; + if (currprefs.cs_cd32fmv) + return 0; rd = getromdatabypath (currprefs.cartfile); if (rd) { if (rd->id == 62) diff --git a/cd32_fmv.cpp b/cd32_fmv.cpp index c882bf2d..b3813f07 100644 --- a/cd32_fmv.cpp +++ b/cd32_fmv.cpp @@ -3,7 +3,7 @@ * * CD32 FMV cartridge * -* Copyright 2008-2010 Toni Wilen +* Copyright 2008-2014 Toni Wilen * */ @@ -18,217 +18,1223 @@ #include "zfile.h" #include "cd32_fmv.h" #include "uae.h" +#include "debug.h" +#include "custom.h" + +#include "cda_play.h" +#include "archivers\mp2\kjmp2.h" +#include "mpeg2.h" +#include "mpeg2convert.h" -#define FMV_DEBUG 1 + +#define FMV_DEBUG 0 +static int fmv_audio_debug = 0; +static int fmv_video_debug = 0; +#define DUMP_VIDEO 0 /* - 0x200000 - 0x23FFFF ROM - 0x240000 io/status (single word register?) + 0x200000 - 0x23FFFF ROM (256k) + 0x240000 io/status (word) 0x2500xx L64111 audio decoder (word registers) + 0x260000 CL450 data port (word) 0x2700xx CL450 video decoder (word registers) - 0x280000 - 0x2FFFFF RAM + 0x280000 - 0x2FFFFF RAM (512k) */ +#define ROM_BASE 0x000000 #define IO_BASE 0x040000 #define L64111_BASE 0x050000 +#define CL450_DATA 0x060000 #define CL450_BASE 0x070000 -#define VRAM_BASE 0x080000 +#define RAM_BASE 0x080000 #define BANK_MASK 0x0F0000 -#define IO_IRQ_L641111 0x4000 -#define IO_IRQ_CL450 0x8000 - -// L64111 registers (from datasheet) -#define A_DATA 0 //0 -#define A_CONTROL1 1 //2 -#define A_CONTROL2 2 //4 -#define A_CONTROL3 3 //6 -#define A_INT1 4 //8 -#define A_INT2 5 //10 -#define A_TCR 6 //12 -#define A_TORH 7 //14 -#define A_TORL 8 //16 -#define A_PARAM1 9 //18 -#define A_PARAM2 10 //20 -#define A_PARAM3 11 //22 -#define A_PRESENT1 12 //24 -#define A_PRESENT2 13 //26 -#define A_PRESENT3 14 //28 -#define A_PRESENT4 15 //30 -#define A_PRESENT5 16 //32 -#define A_FIFO 17 //34 -#define A_CB_STATUS 18 //36 -#define A_CB_WRITE 19 //38 -#define A_CB_READ 20 //40 - -static int fmv_mask; -static uae_u8 *rom; -static int fmv_rom_size = 262144; -static uaecptr fmv_start = 0x00200000; -static int fmv_size = 1048576; - -static uae_u16 l64111regs[32]; -static uae_u16 l64111intmask1, l64111intmask2, l64111intstatus1, l64111intstatus2; +// IO_BASE bits (read) +#define IO_CL450_IRQ 0x8000 // CL450INT_ +#define IO_L64111_IRQ 0x4000 // L64111INT_ +#define IO_CL450_FIFO_STATUS 0x0800 // CL450CFLEVEL +#define IO_L64111_FALF 0x0400 // L64111FALF +#define IO_L64111_FALE 0x0400 // L64111FALE +#define IO_L64111_FEMP 0x0400 // L64111FEMP + +// IO_BASE bits (write) +#define IO_CL450_VIDEO 0x4000 +#define IO_UNK2 0x2000 +#define IO_UNK3 0x1000 +// above three are set/cleared by ROM code +#define IO_L64111_MUTE 0x0200 + +// L64111 registers +#define A_DATA 0 +#define A_CONTROL1 1 +#define A_CONTROL2 2 +#define A_CONTROL3 3 +#define A_INT1 4 +#define A_INT2 5 +#define A_TCR 6 +#define A_TORH 7 +#define A_TORL 8 +#define A_PARAM1 9 +#define A_PARAM2 10 +#define A_PARAM3 11 +#define A_PRESENT1 12 +#define A_PRESENT2 13 +#define A_PRESENT3 14 +#define A_PRESENT4 15 +#define A_PRESENT5 16 +#define A_FIFO 17 +#define A_CB_STATUS 18 +#define A_CB_WRITE 19 +#define A_CB_READ 20 +// L641111 status register 1 +#define ANC_DATA_VALID 0x80 +#define ANC_DATA_FIFO_OVFL 0x40 +#define ANC_DATA_FIO_HFF 0x10 +#define ERR_BUF_OVFL 0x08 +// L641111 status register 2 +#define SYNTAX_ERR_DET 0x40 +#define PTS_AVAILABLE 0x20 +#define SYNC_AUD 0x10 +#define SYNC_SYS 0x08 +#define FRAME_DETECT_IN 0x04 +#define CRC_ERR 0x02 +#define NEWLAST_FRAME 0x01 +#define NEW_FRAME_S 0x01 +#define LAST_FRAME_S 0x80 +// status register 2 mask bits +#define NEW_FRAME 0x02 +#define LAST_FRAME 0x01 + +// CL450 direct access registers +#define CMEM_control 0x80 +#define CMEM_data 0x02 +#define CMEM_dmactrl 0x84 +#define CMEM_status 0x82 +#define CPU_control 0x20 +#define CPU_iaddr 0x3e +#define CPU_imem 0x42 +#define CPU_int 0x54 +#define CPU_intenb 0x26 +#define CPU_pc 0x22 +#define CPU_taddr 0x38 +#define CPU_tmem 0x46 +#define DRAM_refcnt 0xac +#define HOST_control 0x90 +#define HOST_intvecr 0x9c +#define HOST_intvecw 0x98 +#define HOST_newcmd 0x56 +#define HOST_raddr 0x88 +#define HOST_rdata 0x8c +#define HOST_scr0 0x92 +#define HOST_scr1 0x94 +#define HOST_scr2 0x96 +#define VID_control 0xec +#define VID_regdata 0xee +#define VID_chrom 0x0a +#define VID_y 0x00 +// CL450 indirect access registers +#define VID_sela 0x0 +#define VID_selactive 0x8 +#define VID_selaux 0xc +#define VID_selb 0x1 +#define VID_selbor 0x9 +#define VID_selGB 0xb +#define VID_selmode 0x7 +#define VID_selR 0xA +// CL450 commands +#define CL_SetBlank 0x030f +#define CL_SetBorder 0x0407 +#define CL_SetColorMode 0x0111 +#define CL_SetInterruptMask 0x0104 +#define CL_SetThresHold 0x0103 +#define CL_SetVideoFormat 0x0105 +#define CL_SetWindow 0x0406 +#define CL_DisplayStill 0x000c +#define CL_Pause 0x000e +#define CL_Play 0x000d +#define CL_Scan 0x000a +#define CL_SingleStep 0x000b +#define CL_SlowMotion 0x0109 +#define CL_AccessSCR 0x8312 +#define CL_FlushBitStream 0x8102 +#define CL_InquireBufferFullness 0x8001 +#define CL_NewPacket 0x0408 +#define CL_Reset 0x8000 +// CL450 interrupts +#define CL_INT_RDY (1 << 10) +#define CL_INT_END_D (1 << 5) +#define CL_INT_ERR (1 << 0) +#define CL_INT_PIC_D (1 << 6) +#define CL_INT_SEQ_D (1 << 9) +#define CL_INT_SCN (1 << 11) +#define CL_INT_UND (1 << 8) +#define CL_INT_END_V (1 << 4) +#define CL_INT_GOP (1 << 2) +#define CL_INT_PIC_V (1 << 1) +#define CL_INT_SEQ_V (1 << 3) +// CL450 DRAM resident variabels (WORD address) +#define CL_DRAM_SEQ_SEM 0x10 +#define CL_DRAM_SEQ_CONTROL 0x11 +#define CL_DRAM_H_SIZE 0x12 +#define CL_DRAM_V_SIZE 0x13 +#define CL_DRAM_PICTURE_RATE 0x14 +#define CL_DRAM_FLAGS 0x15 +#define CL_DRAM_PIC_SEM 0x16 +#define CL_DRAM_TIME_CODE_0 0x17 +#define CL_DRAM_TIME_CODE_1 0x18 +#define CL_DRAM_TEMPORAL_REF 0x19 +#define CL_DRAM_VER 0xa0 // 0x0200 +#define CL_DRAM_PID 0xa1 // 0x0002 +#define CL_DRAM_CPU_PC 0xa2 + +static uae_u8 *rom, *ram, *audioram; +static const int fmv_rom_size = 262144; +static const int fmv_ram_size = 524288; +static const uaecptr fmv_start = 0x00200000; +static const int fmv_board_size = 1048576; + +#define CL_HMEM_INT_STATUS 0x0a +#define CL450_MPEG_BUFFER 0x10000 +#define CL450_MPEG_BUFFER_SIZE 65536 +#define CL450_MPEG_DECODE_BUFFER (CL450_MPEG_BUFFER + CL450_MPEG_BUFFER_SIZE) +#define CL450_MPEG_DECODE_BUFFER_SIZE (fmv_ram_size - CL450_MPEG_DECODE_BUFFER) + +#define CL450_VIDEO_BUFFERS 8 +#define CL450_VIDEO_BUFFER_SIZE (352 * 288 * 4) + +static uae_u16 cl450_regs[256]; +static double cl450_scr; +#define CL450_IMEM_WORDS (2 * 512) +#define CL450_TMEM_WORDS 128 +#define CL450_HMEM_WORDS 16 +static uae_u16 cl450_imem[CL450_IMEM_WORDS]; +static uae_u16 cl450_tmem[CL450_TMEM_WORDS]; +static uae_u16 cl450_hmem[CL450_HMEM_WORDS]; +#define CL450_VID_REGS 16 +static uae_u16 cl450_vid[CL450_VID_REGS]; +static int cl450_play; +static int cl450_blank; +static uae_u32 cl450_border_color; +static uae_u16 cl450_interruptmask; +static uae_u16 cl450_pending_interrupts; +static uae_u16 cl450_threshold; +static int cl450_buffer_offset; +static int cl450_buffer_empty_cnt; +static int libmpeg_offset; + +struct cl450_videoram +{ + int width; + int height; + uae_u8 data[CL450_VIDEO_BUFFER_SIZE]; +}; +static struct cl450_videoram *videoram; + +static bool cl450_newpacket_mode; +// Real CL450 has command buffer but we don't need to care, +// non-NewPacket commands can be emulated immediately. +#define CL450_NEWPACKET_BUFFER_SIZE 32 +struct cl450_newpacket +{ + uae_u16 length; + uae_u64 pts; + bool pts_valid; +}; +static struct cl450_newpacket cl450_newpacket_buffer[CL450_NEWPACKET_BUFFER_SIZE]; +static int cl450_newpacket_offset_write; +static int cl450_newpacket_offset_read; + +static int cl450_frame_rate; +static int cl450_video_hsync_wait; +static int cl450_videoram_read; +static int cl450_videoram_write; +static int cl450_videoram_cnt; +static int cl450_frame_cnt; + +static uae_u16 l64111_regs[32]; +static uae_u16 l64111intmask[2], l64111intstatus[2]; +#define L64111_CHANNEL_BUFFERS 128 + static uae_u16 io_reg; -static int isdebug (uaecptr addr) +static mpeg2dec_t *mpeg_decoder; +static const mpeg2_info_t *mpeg_info; + +extern addrbank fmv_bank; +extern addrbank fmv_rom_bank; +extern addrbank fmv_ram_bank; + +#if FMV_DEBUG +static int isdebug(uaecptr addr) { #if FMV_DEBUG > 2 if (M68K_GETPC >= 0x200100) return 1; return 0; #endif -#if (FMV_DEBUG == 2) +#if FMV_DEBUG == 2 if (M68K_GETPC >= 0x200100 && (addr & fmv_mask) >= VRAM_BASE) return 1; return 0; #endif return 0; } +#endif -static uae_u8 io_bget (uaecptr addr) +static void do_irq(void) { - addr &= 0xffff; - write_log (_T("FMV: IO byte read access %08x!\n"), addr); - return 0; + if (!(intreq & 8)) { + INTREQ_0(0x8000 | 0x0008); + } } -static uae_u16 io_wget (uaecptr addr) + +static bool l64111_checkint(bool enabled) { - addr &= 0xffff; - if (addr != 0) - return 0; - return io_reg; + bool irq = false; + if (l64111intstatus[0] & l64111intmask[0]) + irq = true; + if (((l64111intstatus[1] << 1) | (l64111intstatus[1] >> 7)) & l64111intmask[1]) + irq = true; + if (irq && enabled) + do_irq(); + return irq; } -static void io_bput (uaecptr addr, uae_u8 v) + +static bool cl450_checkint(bool enabled) { - addr &= 0xffff; - write_log (_T("FMV: IO byte write access %08x!\n"), addr); + bool irq = false; + if (!(cl450_regs[CPU_control] & 1)) + return false; + if (!(cl450_regs[HOST_control] & 0x80)) + irq = true; + if (irq && enabled) + do_irq(); + return irq; } -static void io_wput (uaecptr addr, uae_u16 v) + +void rethink_cd32fmv(void) { - addr &= 0xffff; - if (addr != 0) + if (!ram) return; - write_log (_T("FMV: IO=%04x\n"), v); - io_reg = v; + cl450_checkint(true); + l64111_checkint(true); } -static uae_u8 l64111_bget (uaecptr addr) + +#define L64111_FIFO_LOOKUP 96 +#define L64111_FIFO_BYTES 128 +static uae_u8 l64111_fifo[L64111_FIFO_BYTES]; +static int l64111_fifo_cnt; +static int audio_frame_cnt, audio_frame_size; +static int audio_frame_detect, audio_head_detect; +static int l64111_cb_mask; +#define L64111_CHANNEL_BUFFER_SIZE 2048 + +static kjmp2_context_t mp2; +#define PCM_SECTORS 4 +static cda_audio *cda; +static int audio_data_remaining; +static int audio_skip_size; + +struct zfile *fdump; + +struct fmv_pcmaudio { - write_log (_T("FMV: L64111 byte read access %08x!\n"), addr); - return 0; + bool ready; + signed short pcm[KJMP2_SAMPLES_PER_FRAME * 2]; +}; +static struct fmv_pcmaudio *pcmaudio; + +static void l64111_set_status(int num, uae_u16 mask) +{ + num--; + l64111intstatus[num] |= mask; + l64111_checkint(true); +} + +static void l64111_setvolume(void) +{ + int volume = 32768; + if (l64111_regs[A_CONTROL2] & (1 << 5) || (io_reg & IO_L64111_MUTE)) + volume = 0; + write_log(_T("L64111 mute %d\n"), volume ? 0 : 1); + if (cda) + cda->setvolume(currprefs.sound_volume_cd >= 0 ? currprefs.sound_volume_cd : currprefs.sound_volume, volume, volume); } -static void l64111_bput (uaecptr addr, uae_u8 v) + +static int l64111_get_frame(uae_u8 *data, int remaining) { - write_log (_T("FMV: L64111 byte write access %08x!\n"), addr); + int size, offset; + uae_u8 *memdata; + + if (!audio_frame_size || !audio_data_remaining || !remaining) + return 0; + size = audio_frame_size - audio_frame_cnt > remaining ? remaining : audio_frame_size - audio_frame_cnt; + if (audio_data_remaining >= 0 && size > audio_data_remaining) + size = audio_data_remaining; + offset = l64111_regs[A_CB_WRITE] & l64111_cb_mask; + memdata = audioram + offset * L64111_CHANNEL_BUFFER_SIZE; + memcpy(memdata + audio_frame_cnt, data, size); + audio_frame_cnt += size; + if (audio_data_remaining >= 0) + audio_data_remaining -= size; + if (audio_frame_cnt == audio_frame_size) { + int bytes; + + if (pcmaudio[offset].ready) { + write_log(_T("L64111 buffer overflow!\n")); + } +#if 0 + if (!fdump) + fdump = zfile_fopen(_T("c:\\temp\\1.mp2"), _T("wb")); + + zfile_fwrite(memdata, 1, audio_frame_size, fdump); +#endif + bytes = kjmp2_decode_frame(&mp2, memdata, pcmaudio[offset].pcm); + if (bytes < 4 || bytes > KJMP2_MAX_FRAME_SIZE) { + write_log(_T("mp2 decoding error\n")); + memset(pcmaudio[offset].pcm, 0, KJMP2_SAMPLES_PER_FRAME * 4); + } + pcmaudio[offset].ready = true; + + audio_frame_size = 0; + audio_frame_cnt = 0; + l64111_set_status(2, NEW_FRAME_S); + //write_log(_T("Audio frame %d (%d %d)\n"), offset, l64111_regs[A_CB_STATUS], bytes); + offset++; + l64111_regs[A_CB_WRITE] = offset & l64111_cb_mask; + l64111_regs[A_CB_STATUS]++; + + } + return size; +} + +static const int mpa_bitrates[] = { + -1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1, + -1, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1, + -1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1, + -1, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1, + -1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 +}; +static const int mpa_frequencies[] = { + 44100, 48000, 32000, 0, + 22050, 24000, 16000, 0, + 11025, 12000, 8000, 0 +}; +static const int mpa_samplesperframe[] = { + 384, 384, 384, + 1152, 1152, 1152, + 1152, 576, 576 +}; + +static bool parse_mp2_frame(uae_u8 *header) +{ + int ver, layer, bitrate, freq, padding, bitindex, iscrc; + int samplerate, bitrateidx, channelmode; + int isstereo; + + audio_frame_cnt = 0; + audio_frame_size = 0; + + ver = (header[1] >> 3) & 3; + if (ver != 3) // not MPEG-1 + return false; + ver = 0; + layer = 4 - ((header[1] >> 1) & 3); + if (layer != 2) // not layer-2 + return false; + iscrc = ((header[1] >> 0) & 1) ? 0 : 2; + bitrateidx = (header[2] >> 4) & 15; + if (bitrateidx == 0 || bitrateidx == 15) + return false; // invalid value + freq = mpa_frequencies[(header[2] >> 2) & 3]; + if (!freq) + return false; // invalid value + channelmode = (header[3] >> 6) & 3; + isstereo = channelmode != 3; + if (ver == 0) { + bitindex = layer - 1; + } else { + if (layer == 1) + bitindex = 3; + else + bitindex = 4; + } + bitrate = mpa_bitrates[bitindex * 16 + bitrateidx] * 1000; + if (bitrate <= 0) // invalid value + return false; + padding = (header[2] >> 1) & 1; + samplerate = mpa_samplesperframe[(layer - 1) * 3 + ver]; + audio_frame_size = ((samplerate / 8 * bitrate) / freq) + padding; + audio_frame_cnt = 0; + l64111_cb_mask = layer == 2 ? 63 : 127; + + audio_frame_detect++; + + l64111_regs[A_PARAM1] = ((header[1] << 4) | (header[2] >> 4)) & 0xff; + l64111_regs[A_PARAM2] = ((header[2] << 4) | (header[3] >> 4)) & 0xff; + l64111_regs[A_PARAM3] = ((header[3] << 4)) & 0xff; + + l64111_set_status(2, FRAME_DETECT_IN | (audio_frame_detect == 3 ? SYNC_AUD : 0)); + + return true; +} + +static void l64111_init(void) +{ + audio_head_detect = 0; + audio_frame_detect = 0; + audio_data_remaining = 0; + audio_skip_size = 0; + audio_frame_cnt = 0; + audio_frame_size = 0; + l64111_fifo_cnt = 0; +} + +static void l64111_reset(void) +{ + memset(l64111_regs, 0, sizeof l64111_regs); + l64111intmask[0] = l64111intmask[1] = 0; + l64111intstatus[0] = l64111intstatus[1] = 0; + l64111_regs[A_CONTROL3] = 1 << 7; // AUDIO STREAM_ID_IGNORE=1 + l64111_init(); + l64111_setvolume(); + if (pcmaudio) + memset(pcmaudio, 0, sizeof(struct fmv_pcmaudio) * L64111_CHANNEL_BUFFERS); + write_log(_T("L64111 reset\n")); +} + +static uae_u8 *parse_audio_header(uae_u8 *p) +{ + bool ptsdts; + int cnt; + uae_u16 psize; + uae_u64 pts = 0; + + p += 4; + psize = (p[0] << 8) | p[1]; + //write_log(_T("audio stream header size %d\n"), psize); + p += 2; + if (audio_head_detect < 3) { + audio_head_detect++; + if (audio_head_detect == 3) + l64111_set_status(2, SYNC_SYS); + } + cnt = 16; + while (p[0] == 0xff) { + cnt--; + if (cnt < 0) + return p; + p++; + psize--; + } + if (p[0] == 0x0f) { + p++; + psize--; + } else { + if ((p[0] & 0xc0) == 0x40) { + // STD + p += 2; + psize -= 2; + } + ptsdts = false; + if ((p[0] & 0xf0) == 0x20 || (p[0] & 0xf0) == 0x30) { + if ((p[0] & 0xf0) == 0x30) + ptsdts = true; + // PTS + pts = (((uae_u64)(p[0] >> 1) & 7) << 30); + pts |= ((p[1] >> 0) << 22); + pts |= ((p[2] >> 1) << 15); + pts |= ((p[3] >> 0) << 7); + pts |= ((p[4] >> 1) << 0); + p += 5; + psize -= 5; + if (audio_head_detect >= 3) { + l64111_regs[A_PRESENT1] = pts >> 0; + l64111_regs[A_PRESENT2] = pts >> 8; + l64111_regs[A_PRESENT3] = pts >> 16; + l64111_regs[A_PRESENT4] = pts >> 24; + l64111_regs[A_PRESENT5] = pts >> 32; + //write_log(_T("audio PTS %09llx SCR %09llx\n"), pts, (uae_u64)cl450_scr); + l64111_set_status(2, PTS_AVAILABLE); + } + } + if (ptsdts && (p[0] & 0xf0) == 0x10) { + // DTS + p += 5; + psize -= 5; + } + } + audio_data_remaining = psize; + return p; +} + +static void l64111_parse(void) +{ + bool audio_only = (l64111_regs[A_CONTROL2] & 0x08) != 0; + uae_u8 *p = l64111_fifo; + + if (!(l64111_regs[A_CONTROL1] & 1)) { // START bit set? + l64111_fifo_cnt = 0; + return; + } + + if (audio_only) { + audio_data_remaining = -1; + audio_skip_size = 0; + } + + if (audio_skip_size) { + int size = audio_skip_size > L64111_FIFO_BYTES ? L64111_FIFO_BYTES : audio_skip_size; + p += size; + audio_skip_size -= size; + } + + if (audio_frame_size && audio_data_remaining) + p += l64111_get_frame(p, L64111_FIFO_BYTES - (p - l64111_fifo)); + + while (p - l64111_fifo < L64111_FIFO_LOOKUP || ((p - l64111_fifo) & 1)) { + uae_u8 *op = p; + int size = 0; + + if (!audio_only) { + // check system stream packets + uae_u8 marker = p[3]; + if (p[0] == 0 && p[1] == 0 && p[2] == 1 && (marker & 0x80)) { + int size = (p[4] << 8) | p[5]; + if (marker >= 0xc0 && marker <= 0xdf) { + // audio stream 0 to 31 + bool ignore_stream_id = (l64111_regs[A_CONTROL3] & 0x80) != 0; + if (ignore_stream_id || (marker - 0xc0) == (l64111_regs[A_CONTROL3] & 31)) + p = parse_audio_header(p); + else + p += 4; + } else if (marker == 0xba) { + //write_log(_T("L64111: Pack header\n")); + p += 12; + } else if (marker == 0xbb) { + write_log(_T("L64111: System header, size %d\n"), size); + p += 6; + audio_skip_size = size; + } else if (marker == 0xbe) { + //write_log(_T("L64111: Padding packet size %d\n"), size); + p += 6; + audio_skip_size = size; + } else { + write_log(_T("L64111: Packet %02X, size %d\n"), marker, size); + p += 6; + } + } + } + + if (audio_skip_size) { + int size = audio_skip_size > L64111_FIFO_BYTES - (p - l64111_fifo) ? L64111_FIFO_BYTES - (p - l64111_fifo) : audio_skip_size; + p += size; + audio_skip_size -= size; + } + if (L64111_FIFO_BYTES - (p - l64111_fifo) > 0 && audio_data_remaining) { + if (audio_frame_size) { + p += l64111_get_frame(p, L64111_FIFO_BYTES - (p - l64111_fifo)); + } else if (p[0] == 0xff && (p[1] & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40 | 0x20)) { + if (parse_mp2_frame(p)) + p += l64111_get_frame(p, L64111_FIFO_BYTES - (p - l64111_fifo)); + } + } + + if (p == op) { + p++; + if (audio_data_remaining > 0) + audio_data_remaining--; + } + } + l64111_fifo_cnt = L64111_FIFO_BYTES - (p - l64111_fifo); + if (l64111_fifo_cnt < 0) + l64111_fifo_cnt = 0; + if (l64111_fifo_cnt > 0) + memmove(l64111_fifo, p, l64111_fifo_cnt); } static uae_u16 l64111_wget (uaecptr addr) { + uae_u16 v; + addr >>= 1; addr &= 31; -#if FMV_DEBUG > 0 - write_log (_T("FMV: L64111 read reg %d -> %04x\n"), addr, l64111regs[addr]); -#endif - if (addr == 4) - return l64111intstatus1; - if (addr == 5) - return l64111intstatus1; - return l64111regs[addr]; + if (fmv_audio_debug) { + if (!(addr == A_INT1 || addr == A_INT2 || addr == A_CB_STATUS)) + write_log(_T("L64111 read reg %d -> %04x\n"), addr, l64111_regs[addr]); + } + v = l64111_regs[addr]; + if (addr == A_INT1) { + v = l64111intstatus[0]; + l64111intstatus[0] = 0; + } else if (addr == A_INT2) { + v = l64111intstatus[1] & 0x7f; + l64111intstatus[1] = 0; + } + return v; } static void l64111_wput (uaecptr addr, uae_u16 v) { addr >>= 1; addr &= 31; -#if FMV_DEBUG > 0 - write_log (_T("FMV: L64111 write reg %d = %04x\n"), addr, v); -#endif + if (fmv_audio_debug) { + if (addr != A_DATA) + write_log(_T("L64111 write reg %d = %04x\n"), addr, v); + } - if (addr == 4) { - l64111intmask1 = v; + switch (addr) + { + case A_CONTROL1: + if ((v & 1) != (l64111_regs[addr] & 1)) + l64111_init(); + if ((v & 2)) + l64111_reset(); + if (v & 4) { + l64111_regs[A_CB_WRITE] = 0; + l64111_regs[A_CB_READ] = 0; + l64111_regs[A_CB_STATUS] = 0; + memset(pcmaudio, 0, sizeof(struct fmv_pcmaudio) * L64111_CHANNEL_BUFFERS); + write_log(_T("L64111 buffer reset\n")); + } + break; + case A_CONTROL2: + l64111_setvolume(); + break; + case A_DATA: + if (l64111_fifo_cnt < 0 || l64111_fifo_cnt > L64111_FIFO_BYTES) { + write_log(_T("L641111 fifo overflow!\n")); + l64111_fifo_cnt = 0; + return; + } + l64111_fifo[l64111_fifo_cnt++] = v >> 8; + l64111_fifo[l64111_fifo_cnt++] = v; + if (l64111_fifo_cnt == L64111_FIFO_BYTES) { + l64111_parse(); + } + break; + case A_INT1: + l64111intmask[0] = v; return; - } - if (addr == 5) { - l64111intmask2 = v; + case A_INT2: + l64111intmask[1] = v; return; } - l64111regs[addr] = v; + l64111_regs[addr] = v; } -static uae_u8 cl450_bget (uaecptr addr) +static uae_u8 l64111_bget(uaecptr addr) { - addr &= 0xff; - write_log (_T("FMV: CL450 byte read access %08x!\n"), addr); - return 0; + return l64111_wget(addr); } -static uae_u16 cl450_wget (uaecptr addr) +static void l64111_bput(uaecptr addr, uae_u8 v) { - addr &= 0xff; - addr >>= 1; - write_log (_T("FMV: CL450 read reg %d\n"), addr); - return 0; + l64111_wput(addr, v); } -static void cl450_bput (uaecptr addr, uae_u8 v) + +static void cl450_set_status(uae_u16 mask) { - addr &= 0xff; - write_log (_T("FMV: CL450 byte write access %08x!\n"), addr); + cl450_pending_interrupts |= mask & cl450_interruptmask; + if (cl450_hmem[CL_HMEM_INT_STATUS] == 0) { + cl450_hmem[CL_HMEM_INT_STATUS] = cl450_pending_interrupts; + cl450_pending_interrupts = 0; + cl450_regs[HOST_control] &= ~0x80; + cl450_checkint(true); + } } -static void cl450_wput (uaecptr addr, uae_u16 v) + +static void cl450_write_dram(int addr, uae_u16 w) { - addr &= 0xff; - write_log (_T("FMV: CL450 write reg %d = %04x\n"), addr, v); + if (!ram) + return; + ram[addr * 2 + 0] = w >> 8; + ram[addr * 2 + 1] = w; } -static uae_u8 romram_bget (uaecptr addr) +#if DUMP_VIDEO +static struct zfile *videodump; +#endif + +static void cl450_parse_frame(void) { -#ifdef FMV_DEBUG - if (isdebug (addr)) - write_log (_T("romram_bget %08X PC=%08X\n"), addr, M68K_GETPC); + for (;;) { + mpeg2_state_t mpeg_state = mpeg2_parse(mpeg_decoder); + switch (mpeg_state) + { + case STATE_BUFFER: + { + int bufsize = cl450_buffer_offset; + if (bufsize == 0) + return; + while (bufsize > 0 && cl450_newpacket_mode) { + struct cl450_newpacket *np = &cl450_newpacket_buffer[cl450_newpacket_offset_read]; + if (cl450_newpacket_offset_read == cl450_newpacket_offset_write) + return; + int size = np->length > bufsize ? bufsize : np->length; + + if (np->length == 0) { + write_log(_T("CL450 no matching newpacket!?\n")); + return; + } + + np->length -= size; + bufsize -= size; + if (np->length > 0) + break; + //write_log(_T("CL450: NewPacket %d done\n"), cl450_newpacket_offset_read); + cl450_newpacket_offset_read++; + cl450_newpacket_offset_read &= CL450_NEWPACKET_BUFFER_SIZE - 1; + } +#if DUMP_VIDEO + if (!videodump) + videodump = zfile_fopen(_T("c:\\temp\\1.mpg"), _T("wb")); + zfile_fwrite(&ram[CL450_MPEG_BUFFER], 1, cl450_buffer_offset, videodump); #endif - if (addr >= IO_BASE && addr < VRAM_BASE) - return 0; - return rom[addr]; + memcpy(&ram[CL450_MPEG_DECODE_BUFFER] + libmpeg_offset, &ram[CL450_MPEG_BUFFER], cl450_buffer_offset); + mpeg2_buffer(mpeg_decoder, &ram[CL450_MPEG_DECODE_BUFFER] + libmpeg_offset, &ram[CL450_MPEG_DECODE_BUFFER] + libmpeg_offset + cl450_buffer_offset); + libmpeg_offset += cl450_buffer_offset; + if (libmpeg_offset >= CL450_MPEG_DECODE_BUFFER_SIZE - CL450_MPEG_BUFFER_SIZE) + libmpeg_offset = 0; + cl450_buffer_offset = 0; + } + break; + case STATE_SEQUENCE: + mpeg2_convert(mpeg_decoder, mpeg2convert_rgb32, NULL); + cl450_set_status(CL_INT_SEQ_V); + cl450_frame_rate = mpeg_info->sequence->frame_period ? 27000000 / mpeg_info->sequence->frame_period : 0; + cl450_write_dram(CL_DRAM_PICTURE_RATE, cl450_frame_rate); + cl450_write_dram(CL_DRAM_H_SIZE, mpeg_info->sequence->width); + cl450_write_dram(CL_DRAM_V_SIZE, mpeg_info->sequence->height); + break; + case STATE_PICTURE: + break; + case STATE_GOP: + cl450_write_dram(CL_DRAM_TIME_CODE_0, (mpeg_info->gop->hours << 6) | (mpeg_info->gop->minutes)); + cl450_write_dram(CL_DRAM_TIME_CODE_1, (mpeg_info->gop->seconds << 6) | (mpeg_info->gop->pictures)); + break; + case STATE_SLICE: + case STATE_END: + if (mpeg_info->display_fbuf) { + memcpy(videoram[cl450_videoram_write].data, mpeg_info->display_fbuf->buf[0], CL450_VIDEO_BUFFER_SIZE); + videoram[cl450_videoram_write].width = mpeg_info->sequence->width; + videoram[cl450_videoram_write].height = mpeg_info->sequence->height; + cl450_videoram_write++; + cl450_videoram_write &= CL450_VIDEO_BUFFERS - 1; + cl450_videoram_cnt++; + //write_log(_T("%d\n"), cl450_videoram_cnt); + } + return; + default: + break; + } + } } -static uae_u16 romram_wget (uaecptr addr) + +static void cl450_reset(void) { -#ifdef FMV_DEBUG - if (isdebug (addr)) - write_log (_T("romram_wget %08X PC=%08X\n"), addr, M68K_GETPC); -#endif - if (addr >= IO_BASE && addr < VRAM_BASE) - return 0; - return (rom[addr] << 8) | (rom[addr + 1] << 0); + write_log(_T("CL450 reset\n")); + cl450_play = 0; + cl450_pending_interrupts = 0; + cl450_interruptmask = 0; + cl450_blank = 0; + cl450_border_color = 0; + cl450_threshold = 4096; + cl450_buffer_offset = 0; + cl450_buffer_empty_cnt = 0; + libmpeg_offset = 0; + cl450_newpacket_mode = false; + cl450_newpacket_offset_write = 0; + cl450_newpacket_offset_read = 0; + cl450_videoram_write = 0; + cl450_videoram_read = 0; + cl450_videoram_cnt = 0; + memset(cl450_regs, 0, sizeof cl450_regs); + if (mpeg_decoder) + mpeg2_reset(mpeg_decoder, 1); + if (ram) + memset(ram, 0, 0x100); + cl450_write_dram(CL_DRAM_VER, 0x0200); + cl450_write_dram(CL_DRAM_PID, 0x0002); } -static void ram_bput (uaecptr addr, uae_u8 v) + +static void cl450_init(void) { - if (addr < VRAM_BASE) - return; - rom[addr] = v; - if (isdebug (addr)) { - write_log (_T("ram_bput %08X=%02X PC=%08X\n"), addr, v & 0xff, M68K_GETPC); + write_log(_T("CL450 CPU enabled\n")); + cl450_hmem[15] = 0; + cl450_regs[HOST_newcmd] = 0; + cl450_regs[CMEM_control] = 2; + cl450_regs[HOST_control] = 0x0080 | 0x0001; + cl450_regs[VID_sela] = 0x8000 | 0x2000 | 0x0800 | 0x00c0 | 0x0006; + cl450_regs[VID_selb] = 0x4000 | 0x0900 | 0x0060 | 0x0007; + cl450_regs[HOST_scr2] = 0x1000 | 0x0d00 | 0x00e0; + cl450_regs[HOST_scr1] = 0; + cl450_regs[HOST_scr0] = 0; + cl450_scr = 0; + cl450_write_dram(CL_DRAM_VER, 0x0200); + cl450_write_dram(CL_DRAM_PID, 0x0002); + memset(ram + 0x10, 0, 0x100 - 0x10); +} + +static void cl450_newpacket(void) +{ + struct cl450_newpacket *np = &cl450_newpacket_buffer[cl450_newpacket_offset_write]; + + cl450_newpacket_mode = true; + + np->length = cl450_hmem[1]; + np->pts = 0; + np->pts_valid = false; + if (cl450_hmem[2] & 0x8000) { + uae_u64 v; + v = ((uae_u64)cl450_regs[HOST_scr0] & 7) << 30; + v |= (cl450_regs[HOST_scr1] & 0x7fff) << 15; + v |= cl450_regs[HOST_scr2] & 0x7fff; + np->pts = v; + np->pts_valid = true; } + + if (fmv_video_debug & 1) + write_log(_T("CL450 NewPacket %d: size=%d pts=%09llx v=%d\n"), cl450_newpacket_offset_write, np->length, np->pts, np->pts_valid); + + cl450_newpacket_offset_write++; + cl450_newpacket_offset_write &= CL450_NEWPACKET_BUFFER_SIZE - 1; } -static void ram_wput (uaecptr addr, uae_u16 v) + +static void cl450_from_scr(void) +{ + uae_u64 v = (uae_u64)cl450_scr; + cl450_regs[HOST_scr0] &= ~7; + cl450_regs[HOST_scr0] |= (v >> 30) & 7; + cl450_regs[HOST_scr1] = (v >> 15) & 0x7fff; + cl450_regs[HOST_scr2] = v & 0x7fff; +} + +static void cl450_to_scr(void) { - if (addr < VRAM_BASE) + uae_u64 v; + v = ((uae_u64)cl450_regs[HOST_scr0] & 7) << 30; + v |= (cl450_regs[HOST_scr1] & 0x7fff) << 15; + v |= cl450_regs[HOST_scr2] & 0x7fff; + cl450_scr = v; +} + +static void cl450_reset_cmd(void) +{ + cl450_blank = 1; + cl450_play = 0; + cl450_newpacket_offset_read = 0; + cl450_newpacket_offset_write = 0; + cl450_newpacket_mode = false; + cl450_interruptmask = 0; + cl450_buffer_offset = 0; + cl450_buffer_empty_cnt = 0; +} + +static void cl450_newcmd(void) +{ +// write_log(_T("* CL450 Command %04x\n"), cl450_hmem[0]); +// for (int i = 1; i <= 4; i++) +// write_log(_T("%02d: %04x\n"), i, cl450_hmem[i]); + switch (cl450_hmem[0]) + { + case CL_Play: + cl450_play = 1; + write_log(_T("CL450 PLAY\n")); + break; + case CL_Pause: + if (cl450_play > 0) { + // pause clears SCR + cl450_scr = 0; + cl450_to_scr(); + } + cl450_play = -cl450_play; + write_log(_T("CL450 PAUSE\n")); + break; + case CL_NewPacket: + cl450_newpacket(); + break; + case CL_InquireBufferFullness: + cl450_hmem[0x0b] = cl450_buffer_offset; + if (fmv_video_debug & 1) + write_log(_T("CL450 InquireBufferFullness (%d)\n"), cl450_buffer_offset); + break; + case CL_SetBlank: + cl450_blank = cl450_hmem[1] & 1; + write_log(_T("CL450 blank = %d\n"), cl450_blank); + break; + case CL_SetBorder: + cl450_border_color = ((cl450_hmem[3] & 0xff) << 16) | cl450_hmem[4]; + write_log(_T("CL450 SetBorder %08x\n"), cl450_border_color); + cd32_fmv_new_border_color(cl450_border_color); + break; + case CL_SetColorMode: + write_log(_T("CL450 SetColorMode\n")); + break; + case CL_SetInterruptMask: + cl450_interruptmask = cl450_hmem[1]; + write_log(_T("CL450 SetInterruptMask %04x\n"), cl450_interruptmask); + break; + case CL_SetThresHold: + cl450_threshold = cl450_hmem[1]; + write_log(_T("CL450 SetThresHold %d\n"), cl450_threshold); + break; + case CL_SetVideoFormat: + write_log(_T("CL450 SetVideoFormat\n")); + break; + case CL_SetWindow: + write_log(_T("CL450 SetWindow\n")); + break; + case CL_AccessSCR: + if (cl450_hmem[1] & 0x8000) { + cl450_from_scr(); + cl450_hmem[1] = 0x8000 | (cl450_regs[HOST_scr0] & 7); + cl450_hmem[2] = cl450_regs[HOST_scr1] & 0x7fff; + cl450_hmem[3] = cl450_regs[HOST_scr2] & 0x7fff; + } else { + cl450_regs[HOST_scr0] = cl450_hmem[1] & 7; + cl450_regs[HOST_scr1] = cl450_hmem[2] & 0x7fff; + cl450_regs[HOST_scr2] = cl450_hmem[3] & 0x7fff; + cl450_to_scr(); + } + if (fmv_video_debug & 1) + write_log(_T("CL450 AccessSCR %c %09llx (%04x %04x %04x)\n"), + (cl450_hmem[1] & 0x8000) ? 'R' : 'W', (uae_u64)cl450_scr, + cl450_regs[HOST_scr0], cl450_regs[HOST_scr1], cl450_regs[HOST_scr2]); + break; + case CL_Reset: + write_log(_T("CL450 Reset\n")); + cl450_reset_cmd(); + break; + case CL_FlushBitStream: + write_log(_T("CL450 CL_FlushBitStream\n")); + cl450_buffer_offset = 0; + memset(cl450_newpacket_buffer, 0, sizeof cl450_newpacket_buffer); + cl450_newpacket_offset_read = cl450_newpacket_offset_write = 0; + break; + default: + write_log(_T("CL450 unsupported command %04x\n"), cl450_hmem[0]); + break; + } + + cl450_regs[HOST_newcmd] = 0; +} + +static uae_u16 cl450_wget (uaecptr addr) +{ + uae_u16 v = 0; + addr &= 0xfe; + + switch (addr) + { + case CMEM_dmactrl: + write_log(_T("CL450 CMEM_dmactrl\n")); + break; + case HOST_intvecr: + v = cl450_regs[HOST_intvecr]; + break; + case HOST_control: + v = cl450_regs[HOST_control]; + break; + case HOST_raddr: + v = cl450_regs[HOST_raddr]; + break; + case HOST_rdata: + v = cl450_hmem[cl450_regs[HOST_raddr]]; + break; + case HOST_newcmd: + v = cl450_regs[HOST_newcmd]; + break; + case CPU_iaddr: + v = cl450_regs[CPU_iaddr]; + break; + case CPU_taddr: + v = cl450_regs[CPU_taddr]; + break; + case CPU_pc: + v = cl450_regs[CPU_pc]; + break; + case CPU_control: + v = cl450_regs[CPU_control]; + break; + case VID_control: + v = cl450_regs[VID_control]; + break; + case VID_regdata: + v = cl450_vid[cl450_regs[VID_control] >> 1]; + break; + default: + write_log(_T("CL450 unknown register %02x read\n"), addr); + return v; + } + + if (fmv_video_debug & 2) + write_log (_T("CL450 read reg %02x %04x\n"), addr, v); + return v; +} + +static void cl450_data_wput(uae_u16 v) +{ + ram[CL450_MPEG_BUFFER + cl450_buffer_offset + 0] = v >> 8; + ram[CL450_MPEG_BUFFER + cl450_buffer_offset + 1] = v; + if (cl450_buffer_offset < CL450_MPEG_BUFFER_SIZE - 2) + cl450_buffer_offset += 2; +} + +static void cl450_wput(uaecptr addr, uae_u16 v) +{ + addr &= 0xfe; + + if (fmv_video_debug & 2) + write_log(_T("CL450 write reg %02x %04x\n"), addr, v); + + switch (addr) + { + case CMEM_data: + cl450_data_wput(v); + break; + case CMEM_control: + cl450_regs[CMEM_control] = v; + if (v & 0x40) + cl450_reset(); + write_log(_T("CL450 CMEM_control %04x\n"), v); + break; + case CMEM_dmactrl: + cl450_regs[CMEM_dmactrl] = v; + write_log(_T("CL450 CMEM_dmactrl %04x\n"), v); + break; + case HOST_intvecw: + cl450_regs[HOST_intvecr] = v; + write_log(_T("CL450 HOST_intvecw %04x\n"), v); + break; + case HOST_control: + cl450_regs[HOST_control] = v; + //write_log(_T("CL450 HOST_control %04x\n"), v); + break; + case HOST_raddr: + cl450_regs[HOST_raddr] = v & 15; + //write_log(_T("CL450 HOST_raddr %04x\n"), v); + break; + case HOST_rdata: + cl450_hmem[cl450_regs[HOST_raddr]] = v; + //write_log(_T("CL450 HOST_rdata %d %04x\n"), cl450_regs[HOST_raddr], v); + cl450_regs[HOST_raddr]++; + cl450_regs[HOST_raddr] &= CL450_HMEM_WORDS - 1; + break; + case HOST_newcmd: + cl450_regs[HOST_newcmd] = v; + cl450_newcmd(); + break; + case CPU_pc: + cl450_regs[CPU_pc] = v; + write_log(_T("CL450 CPU_pc %04x\n"), v); + break; + case CPU_control: + write_log(_T("CL450 CPU_control %04x\n"), v); + if (!(cl450_regs[CPU_control] & 1) && (v & 1)) { + cl450_init(); + } + cl450_regs[CPU_control] = v & 1; + break; + case DRAM_refcnt: + cl450_regs[DRAM_refcnt] = v; + write_log(_T("CL450 DRAM_refcnt %04x\n"), v); + break; + case CPU_imem: + cl450_regs[CPU_iaddr] &= CL450_IMEM_WORDS - 1; + cl450_imem[CPU_iaddr] = v; + cl450_regs[CPU_iaddr]++; + cl450_regs[CPU_iaddr] &= CL450_IMEM_WORDS - 1; + break; + case CPU_iaddr: + cl450_regs[CPU_iaddr] = v & (CL450_IMEM_WORDS - 1); + write_log(_T("CL450 CPU_iaddr %04x\n"), v); + break; + case CPU_tmem: + cl450_regs[CPU_taddr] &= CL450_TMEM_WORDS - 1; + cl450_tmem[CPU_taddr] = v; + cl450_regs[CPU_taddr]++; + cl450_regs[CPU_taddr] &= CL450_TMEM_WORDS - 1; + break; + case CPU_taddr: + cl450_regs[CPU_taddr] = v & (CL450_TMEM_WORDS - 1); + write_log(_T("CL450 CPU_taddr %04x\n"), v); + break; + case VID_control: + cl450_regs[VID_control] = v & ((CL450_VID_REGS - 1) << 1); + break; + case VID_regdata: + cl450_vid[cl450_regs[VID_control] >> 1] = v; + write_log(_T("CL450 vid reg %02x = %04x\n"), cl450_regs[VID_control] >> 1, v); + break; + case HOST_scr0: + cl450_regs[HOST_scr0] = v; + break; + case HOST_scr1: + cl450_regs[HOST_scr1] = v; + break; + case HOST_scr2: + cl450_regs[HOST_scr2] = v; + break; + default: + write_log(_T("CL450 write unknown register %02x = %04x\n"), addr, v); return; - rom[addr + 0] = v >> 8; - rom[addr + 1] = v >> 0; - if (isdebug (addr)) { - write_log (_T("ram_wput %08X=%04X PC=%08X\n"), addr, v & 0xffff, M68K_GETPC); } } +static uae_u8 cl450_bget(uaecptr addr) +{ + return cl450_wget(addr); +} +static void cl450_bput(uaecptr addr, uae_u8 v) +{ + cl450_wput(addr, v); +} + +static uae_u8 io_bget(uaecptr addr) +{ + addr &= 0xffff; + write_log(_T("FMV: IO byte read access %08x!\n"), addr); + return 0; +} +static uae_u16 io_wget(uaecptr addr) +{ + uae_u16 v = 0; + addr &= 0xffff; + if (addr != 0) + return 0; + v |= IO_CL450_IRQ | IO_L64111_IRQ | IO_CL450_FIFO_STATUS; + if (cl450_checkint(false)) + v &= ~IO_CL450_IRQ; + if (l64111_checkint(false)) + v &= ~IO_L64111_IRQ; + return v; +} +static void io_bput(uaecptr addr, uae_u8 v) +{ + addr &= 0xffff; + write_log(_T("FMV: IO byte write access %08x!\n"), addr); +} +static void io_wput(uaecptr addr, uae_u16 v) +{ + addr &= 0xffff; + if (addr != 0) + return; + write_log(_T("FMV: IO=%04x\n"), v); + io_reg = v; + l64111_setvolume(); + cd32_fmv_state((io_reg & IO_CL450_VIDEO) ? 1 : 0); +} + static uae_u32 REGPARAM2 fmv_wget (uaecptr addr) { uae_u32 v; - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; + addr -= fmv_start & fmv_bank.mask; + addr &= fmv_bank.mask; int mask = addr & BANK_MASK; if (mask == L64111_BASE) v = l64111_wget (addr); @@ -236,10 +1242,8 @@ static uae_u32 REGPARAM2 fmv_wget (uaecptr addr) v = cl450_wget (addr); else if (mask == IO_BASE) v = io_wget (addr); - else - v = romram_wget (addr); -#ifdef FMV_DEBUG +#if FMV_DEBUG if (isdebug (addr)) write_log (_T("fmv_wget %08X=%04X PC=%08X\n"), addr, v, M68K_GETPC); #endif @@ -250,7 +1254,7 @@ static uae_u32 REGPARAM2 fmv_lget (uaecptr addr) { uae_u32 v; v = (fmv_wget (addr) << 16) | (fmv_wget (addr + 2) << 0); -#ifdef FMV_DEBUG +#if FMV_DEBUG if (isdebug (addr)) write_log (_T("fmv_lget %08X=%08X PC=%08X\n"), addr, v, M68K_GETPC); #endif @@ -260,8 +1264,8 @@ static uae_u32 REGPARAM2 fmv_lget (uaecptr addr) static uae_u32 REGPARAM2 fmv_bget (uaecptr addr) { uae_u32 v; - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; + addr -= fmv_start & fmv_bank.mask; + addr &= fmv_bank.mask; int mask = addr & BANK_MASK; if (mask == L64111_BASE) v = l64111_bget (addr); @@ -269,16 +1273,14 @@ static uae_u32 REGPARAM2 fmv_bget (uaecptr addr) v = cl450_bget (addr); else if (mask == IO_BASE) v = io_bget (addr); - else - v = romram_bget (addr); return v; } static void REGPARAM2 fmv_wput (uaecptr addr, uae_u32 w) { - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; -#ifdef FMV_DEBUG + addr -= fmv_start & fmv_bank.mask; + addr &= fmv_bank.mask; +#if FMV_DEBUG if (isdebug (addr)) write_log (_T("fmv_wput %04X=%04X PC=%08X\n"), addr, w & 65535, M68K_GETPC); #endif @@ -288,14 +1290,14 @@ static void REGPARAM2 fmv_wput (uaecptr addr, uae_u32 w) else if (mask == CL450_BASE) cl450_wput (addr, w); else if (mask == IO_BASE) - io_wput (addr, w); - else - ram_wput (addr, w); + io_wput(addr, w); + else if (mask == CL450_DATA) + cl450_data_wput(w); } static void REGPARAM2 fmv_lput (uaecptr addr, uae_u32 w) { -#ifdef FMV_DEBUG +#if FMV_DEBUG if (isdebug (addr)) write_log (_T("fmv_lput %08X=%08X PC=%08X\n"), addr, w, M68K_GETPC); #endif @@ -305,8 +1307,8 @@ static void REGPARAM2 fmv_lput (uaecptr addr, uae_u32 w) static void REGPARAM2 fmv_bput (uaecptr addr, uae_u32 w) { - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; + addr -= fmv_start & fmv_bank.mask; + addr &= fmv_bank.mask; int mask = addr & BANK_MASK; if (mask == L64111_BASE) l64111_bput (addr, w); @@ -314,91 +1316,234 @@ static void REGPARAM2 fmv_bput (uaecptr addr, uae_u32 w) cl450_bput (addr, w); else if (mask == IO_BASE) io_bput (addr, w); - else - ram_bput (addr, w); } -static uae_u32 REGPARAM2 fmv_wgeti (uaecptr addr) -{ - uae_u32 v = 0; - uae_u8 *m; -#ifdef JIT - special_mem |= S_READ; -#endif - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; - m = rom + addr; - if (addr < fmv_rom_size) - return do_get_mem_word ((uae_u16 *)m); -#ifdef FMV_DEBUG - write_log (_T("fmv_wgeti %08X %08X PC=%08X\n"), addr, v, M68K_GETPC); -#endif - return v; -} +static double max_sync_vpos; +static double remaining_sync_vpos; -static uae_u32 REGPARAM2 fmv_lgeti (uaecptr addr) +void cd32_fmv_set_sync(double svpos) { - uae_u32 v = 0; - uae_u8 *m; -#ifdef JIT - special_mem |= S_READ; -#endif - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; - m = rom + addr; - if (addr < fmv_rom_size) - return do_get_mem_long ((uae_u32 *)m); -#ifdef FMV_DEBUG - write_log (_T("fmv_lgeti %08X %08X PC=%08X\n"), addr, v, M68K_GETPC); -#endif - return v; + max_sync_vpos = svpos; } -static int REGPARAM2 fmv_check (uaecptr addr, uae_u32 size) +void cd32_fmv_hsync_handler(void) { - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; - return (addr + size) <= fmv_size; + if (!ram) + return; + + if (cl450_play > 0) + cl450_scr += 90000.0 / hblank_hz; + + if (cl450_video_hsync_wait > 0) + cl450_video_hsync_wait--; + if (cl450_video_hsync_wait == 0) { + cl450_set_status(CL_INT_PIC_D); + if (cl450_videoram_cnt > 0) { + cd32_fmv_new_image(videoram[cl450_videoram_read].width, videoram[cl450_videoram_read].height, cl450_blank ? NULL : videoram[cl450_videoram_read].data); + cl450_videoram_read++; + cl450_videoram_read &= CL450_VIDEO_BUFFERS - 1; + cl450_videoram_cnt--; + } + cl450_video_hsync_wait = max_sync_vpos; + while (remaining_sync_vpos >= 1.0) { + cl450_video_hsync_wait++; + remaining_sync_vpos -= 1.0; + } + remaining_sync_vpos += max_sync_vpos - cl450_video_hsync_wait; + if (cl450_frame_rate < 40) + cl450_video_hsync_wait *= 2; + } + + if (vpos & 7) + return; + + if (cl450_play > 0) { + if (cl450_newpacket_mode && cl450_buffer_offset < cl450_threshold) { + int newpacket_len = 0; + for (int i = 0; i < CL450_NEWPACKET_BUFFER_SIZE; i++) + newpacket_len += cl450_newpacket_buffer[i].length; + if (cl450_buffer_offset >= newpacket_len - 6) + cl450_set_status(CL_INT_RDY); + } + + if (cl450_buffer_offset >= 512 && cl450_videoram_cnt < CL450_VIDEO_BUFFERS - 1) { + cl450_parse_frame(); + } + } } -static uae_u8 *REGPARAM2 fmv_xlate (uaecptr addr) +void cd32_fmv_vsync_handler(void) { - addr -= fmv_start & fmv_mask; - addr &= fmv_mask; - return rom + addr; + int bufnum; + int offset, needsectors; + bool play0, play1; + + if (!ram) + return; + + if (cl450_buffer_offset == 0) { + if (cl450_buffer_empty_cnt >= 2) + cl450_set_status(CL_INT_UND); + else + cl450_buffer_empty_cnt++; + } else { + cl450_buffer_empty_cnt = 0; + } + + + if (!cda || !(l64111_regs[A_CONTROL1] & 1)) + return; + play0 = cda->isplaying(0); + play1 = cda->isplaying(1); + needsectors = PCM_SECTORS; + if (!play0 && !play1) { + needsectors *= 2; + write_log(_T("L64111 buffer underflow\n")); + } + offset = l64111_regs[A_CB_READ] & l64111_cb_mask; + for (int i = 0; i < needsectors; i++) { + int offset2 = (offset + i) & l64111_cb_mask; + if (!pcmaudio[offset2].ready) + return; + } + + bufnum = 0; + if (play0) { + if (play1) + return; + bufnum = 1; + } + for (int i = 0; i < PCM_SECTORS; i++) { + int offset2 = (offset + i) & l64111_cb_mask; + memcpy(cda->buffers[bufnum] + i * KJMP2_SAMPLES_PER_FRAME * 4, pcmaudio[offset2].pcm, KJMP2_SAMPLES_PER_FRAME * 4); + pcmaudio[offset2].ready = false; + } + cda->play(bufnum); + offset += PCM_SECTORS; + offset &= l64111_cb_mask; + l64111_regs[A_CB_READ] = offset; + l64111_regs[A_CB_STATUS] -= PCM_SECTORS; } static addrbank fmv_bank = { fmv_lget, fmv_wget, fmv_bget, fmv_lput, fmv_wput, fmv_bput, - fmv_xlate, fmv_check, NULL, _T("CD32 FMV module"), - fmv_lgeti, fmv_wgeti, ABFLAG_ROM | ABFLAG_IO + default_xlate, default_check, NULL, _T("CD32 FMV IO"), + fmv_lget, fmv_wget, ABFLAG_IO }; +MEMORY_FUNCTIONS_NOJIT(fmv_rom); + +static addrbank fmv_rom_bank = { + fmv_rom_lget, fmv_rom_wget, fmv_rom_bget, + fmv_rom_lput, fmv_rom_wput, fmv_rom_bput, + fmv_rom_xlate, fmv_rom_check, NULL, _T("CD32 FMV ROM"), + fmv_rom_lget, fmv_rom_wget, ABFLAG_ROM +}; +MEMORY_FUNCTIONS_NOJIT(fmv_ram); + +static addrbank fmv_ram_bank = { + fmv_ram_lget, fmv_ram_wget, fmv_ram_bget, + fmv_ram_lput, fmv_ram_wput, fmv_ram_bput, + fmv_ram_xlate, fmv_ram_check, NULL, _T("CD32 FMV RAM"), + fmv_ram_lget, fmv_ram_wget, ABFLAG_RAM +}; + +void cd32_fmv_reset(void) +{ + if (ram) + memset(ram, 0, fmv_ram_size); + cd32_fmv_state(0); +} + +void cd32_fmv_free(void) +{ + mapped_free(rom); + rom = NULL; + mapped_free(ram); + ram = NULL; + xfree(audioram); + audioram = NULL; + xfree(videoram); + videoram = NULL; + if (cda) { + cda->wait(0); + cda->wait(1); + delete cda; + } + cda = NULL; + xfree(pcmaudio); + pcmaudio = NULL; + if (mpeg_decoder) + mpeg2_close(mpeg_decoder); + mpeg_decoder = NULL; + cl450_reset(); + l64111_reset(); +} + void cd32_fmv_init (uaecptr start) { - int ids[] = { 23, 74, -1 }; - struct romlist *rl = getromlistbyids (ids); - struct romdata *rd; struct zfile *z; - write_log (_T("CD32 FMV mapped @$%lx\n"), start); - if (start != fmv_start) - return; - if (!rl) + cd32_fmv_free(); + write_log (_T("CD32 FMV mapped @$%x\n"), start); + if (start != fmv_start) { + write_log(_T("CD32 FMV invalid base address!\n")); return; - rd = rl->rd; - z = read_rom (rd); + } + z = read_rom_name(currprefs.cartfile); + if (!z) { + int ids[] = { 74, 23, -1 }; + struct romdata *rd; + struct romlist *rl = getromlistbyids (ids); + if (rl) { + rd = rl->rd; + write_log (_T("CD32 FMV ROM %d.%d\n"), rd->ver, rd->rev); + z = read_rom (rd); + } + } if (z) { - write_log (_T("CD32 FMV ROM %d.%d\n"), rd->ver, rd->rev); - rom = mapped_malloc (fmv_size, _T("fast")); - if (rom) - zfile_fread (rom, rd->size, 1, z); + rom = mapped_malloc(fmv_rom_size, _T("fmv_rom")); + if (rom) { + int size = zfile_size(z); + zfile_fread (rom, size > fmv_rom_size ? fmv_rom_size : size, 1, z); + } zfile_fclose (z); } - fmv_mask = fmv_size - 1; - fmv_bank.baseaddr = rom; - map_banks (&fmv_bank, start >> 16, fmv_size >> 16, 0); + if (!rom) { + write_log(_T("CD32 FMV without ROM is not supported.\n")); + return; + } + if (!audioram) + audioram = xmalloc(uae_u8, 262144); + if (!videoram) + videoram = xmalloc(struct cl450_videoram, CL450_VIDEO_BUFFERS); + if (!ram) + ram = mapped_malloc(fmv_ram_size, _T("fmv_ram")); + if (!pcmaudio) + pcmaudio = xcalloc(struct fmv_pcmaudio, L64111_CHANNEL_BUFFERS); + + kjmp2_init(&mp2); + if (!cda) { + cda = new cda_audio(PCM_SECTORS, KJMP2_SAMPLES_PER_FRAME * 4); + l64111_setvolume(); + } + if (!mpeg_decoder) { + mpeg_decoder = mpeg2_init(); + mpeg_info = mpeg2_info(mpeg_decoder); + } + + fmv_rom_bank.mask = fmv_rom_size - 1; + fmv_rom_bank.baseaddr = rom; + fmv_rom_bank.allocated = fmv_rom_size; + fmv_ram_bank.mask = fmv_ram_size - 1; + fmv_ram_bank.baseaddr = ram; + fmv_ram_bank.allocated = fmv_ram_size; + fmv_bank.mask = fmv_board_size - 1; + map_banks(&fmv_rom_bank, (fmv_start + ROM_BASE) >> 16, fmv_rom_size >> 16, 0); + map_banks(&fmv_ram_bank, (fmv_start + RAM_BASE) >> 16, fmv_ram_size >> 16, 0); + map_banks(&fmv_bank, (fmv_start + IO_BASE) >> 16, (RAM_BASE - IO_BASE) >> 16, 0); + cd32_fmv_reset(); } diff --git a/cd32_fmv_genlock.cpp b/cd32_fmv_genlock.cpp new file mode 100644 index 00000000..c49e4b90 --- /dev/null +++ b/cd32_fmv_genlock.cpp @@ -0,0 +1,110 @@ +/* +* UAE - The Un*x Amiga Emulator +* +* CD32 FMV video genlock +* +* Copyright 2014 Toni Wilen +* +*/ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "options.h" +#include "cd32_fmv.h" +#include "xwin.h" + +static uae_u8 *mpeg_out_buffer; +static int mpeg_width, mpeg_height; +static uae_u32 fmv_border_color; +int cd32_fmv_active; + +// According to schematics there is at least 3 (possible more) +// "genlock modes" but they seem to be unused, at least ROM +// mpeg player software never sets any genlock bits. + +// this is probably not how it actually works. +#define GENLOCK_VAL 0x20 + +#define MPEG_PIXBYTES 4 +#define MAX_MPEG_WIDTH 352 +#define MAX_MPEG_HEIGHT 288 + +void cd32_fmv_new_border_color(uae_u32 bordercolor) +{ + fmv_border_color = bordercolor; +} + +void cd32_fmv_new_image(int w, int h, uae_u8 *s) +{ + if (!mpeg_out_buffer) + mpeg_out_buffer = xmalloc(uae_u8, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES); + if (s == NULL || w > MAX_MPEG_WIDTH || h > MAX_MPEG_HEIGHT) { + memset(mpeg_out_buffer, 0, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES); + mpeg_width = MAX_MPEG_WIDTH; + mpeg_height = MAX_MPEG_HEIGHT; + return; + } + memcpy(mpeg_out_buffer, s, w * h * MPEG_PIXBYTES); + mpeg_width = w; + mpeg_height = h; +} + +void cd32_fmv_state(int state) +{ + cd32_fmv_active = state; +} + +// slow software method but who cares. + +void cd32_fmv_genlock(struct vidbuffer *vbin, struct vidbuffer *vbout) +{ + int hoffset, voffset, mult; + int w = vbin->outwidth; + int h = vbin->outheight; + int d = vbin->pixbytes; + + mult = 1; + for (;;) { + if (mult < 4 && mpeg_width * (mult << 1) <= w && mpeg_height * (mult << 1) <= h) { + mult <<= 1; + } + else { + break; + } + } + + hoffset = (w / mult - mpeg_width) / 2; + voffset = (h / mult - mpeg_height) / 2; + + if (hoffset < 0) + hoffset = 0; + if (voffset < 0) + voffset = 0; + + for (int hh = 0, sh = -voffset; hh < h; sh++, hh += mult) { + for (int h2 = 0; h2 < mult; h2++) { + uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + h2 + voffset); + uae_u32 *d32 = (uae_u32*)d8; + uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + h2 + voffset) ; + uae_u32 *srcp = NULL; + if (sh >= 0 && sh < mpeg_height) + srcp = (uae_u32*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES); + for (int ww = 0, sw = -hoffset; ww < w; sw++, ww += mult) { + uae_u32 sv = fmv_border_color; + if (sw >= 0 && sw < mpeg_width && srcp) + sv = srcp[sw]; + for (int w2 = 0; w2 < mult; w2++) { + uae_u32 v; + if (s8[0] >= GENLOCK_VAL) { + v = *((uae_u32*)s8); + } else { + v = sv; + } + *d32++ = v; + s8 += d; + } + } + } + } +} diff --git a/cfgfile.cpp b/cfgfile.cpp index df1dadb7..5f051d28 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -180,7 +180,7 @@ static const TCHAR *magiccursors[] = { _T("both"), _T("native"), _T("host"), 0 } static const TCHAR *autoscale[] = { _T("none"), _T("auto"), _T("standard"), _T("max"), _T("scale"), _T("resize"), _T("center"), _T("manual"), _T("integer"), _T("integer_auto"), 0 }; static const TCHAR *autoscale_rtg[] = { _T("resize"), _T("scale"), _T("center"), _T("integer"), 0 }; static const TCHAR *joyportmodes[] = { _T(""), _T("mouse"), _T("mousenowheel"), _T("djoy"), _T("gamepad"), _T("ajoy"), _T("cdtvjoy"), _T("cd32joy"), _T("lightpen"), 0 }; -static const TCHAR *joyaf[] = { _T("none"), _T("normal"), _T("toggle"), 0 }; +static const TCHAR *joyaf[] = { _T("none"), _T("normal"), _T("toggle"), _T("always"), 0 }; static const TCHAR *epsonprinter[] = { _T("none"), _T("ascii"), _T("epson_matrix_9pin"), _T("epson_matrix_24pin"), _T("epson_matrix_48pin"), 0 }; static const TCHAR *aspects[] = { _T("none"), _T("vga"), _T("tv"), 0 }; static const TCHAR *vsyncmodes[] = { _T("false"), _T("true"), _T("autoswitch"), 0 }; @@ -1391,8 +1391,9 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type) cfgfile_dwrite_bool (f, _T("ksmirror_a8"), p->cs_ksmirror_a8); cfgfile_dwrite_bool (f, _T("cd32cd"), p->cs_cd32cd); cfgfile_dwrite_bool (f, _T("cd32c2p"), p->cs_cd32c2p); - cfgfile_dwrite_bool (f, _T("cd32nvram"), p->cs_cd32nvram); - cfgfile_dwrite_bool (f, _T("cdtvcd"), p->cs_cdtvcd); + cfgfile_dwrite_bool(f, _T("cd32nvram"), p->cs_cd32nvram); + cfgfile_dwrite_bool(f, _T("cd32fmv"), p->cs_cd32fmv); + cfgfile_dwrite_bool(f, _T("cdtvcd"), p->cs_cdtvcd); cfgfile_dwrite_bool (f, _T("cdtvram"), p->cs_cdtvram); cfgfile_dwrite (f, _T("cdtvramcard"), _T("%d"), p->cs_cdtvcard); cfgfile_dwrite_str (f, _T("ide"), p->cs_ide == IDE_A600A1200 ? _T("a600/a1200") : (p->cs_ide == IDE_A4000 ? _T("a4000") : _T("none"))); @@ -3514,8 +3515,9 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH || cfgfile_yesno (option, value, _T("cpu_no_unimplemented"), &p->int_no_unimplemented) || cfgfile_yesno (option, value, _T("cd32cd"), &p->cs_cd32cd) || cfgfile_yesno (option, value, _T("cd32c2p"), &p->cs_cd32c2p) - || cfgfile_yesno (option, value, _T("cd32nvram"), &p->cs_cd32nvram) - || cfgfile_yesno (option, value, _T("cdtvcd"), &p->cs_cdtvcd) + || cfgfile_yesno(option, value, _T("cd32nvram"), &p->cs_cd32nvram) + || cfgfile_yesno(option, value, _T("cd32fmv"), &p->cs_cd32fmv) + || cfgfile_yesno(option, value, _T("cdtvcd"), &p->cs_cdtvcd) || cfgfile_yesno (option, value, _T("cdtvram"), &p->cs_cdtvram) || cfgfile_yesno (option, value, _T("a1000ram"), &p->cs_a1000ram) || cfgfile_yesno (option, value, _T("pcmcia"), &p->cs_pcmcia) @@ -5308,7 +5310,7 @@ void default_prefs (struct uae_prefs *p, int type) p->cs_mbdmac = 0; p->a2091 = 0; p->a4091 = 0; - p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = false; + p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = p->cs_cd32fmv = false; p->cs_cdtvcd = p->cs_cdtvram = false; p->cs_cdtvcard = 0; p->cs_pcmcia = 0; @@ -5562,7 +5564,7 @@ static void buildin_default_prefs (struct uae_prefs *p) p->cs_mbdmac = 0; p->a2091 = false; p->a4091 = false; - p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = false; + p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = p->cs_cd32fmv = false; p->cs_cdtvcd = p->cs_cdtvram = p->cs_cdtvcard = false; p->cs_ide = 0; p->cs_pcmcia = 0; @@ -5810,10 +5812,10 @@ static int bip_cdtv (struct uae_prefs *p, int config, int compa, int romcheck) static int bip_cd32 (struct uae_prefs *p, int config, int compa, int romcheck) { - int roms[2]; + int roms[3]; buildin_default_prefs_68020 (p); - p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = 1; + p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = true; p->nr_floppies = 0; p->floppyslots[0].dfxtype = DRV_NONE; p->floppyslots[1].dfxtype = DRV_NONE; @@ -5834,7 +5836,10 @@ static int bip_cd32 (struct uae_prefs *p, int config, int compa, int romcheck) return 0; } if (config > 0) { - roms[0] = 23; + p->cs_cd32fmv = true; + roms[0] = 74; + roms[1] = 23; + roms[2] = -1; if (!configure_rom (p, roms, romcheck)) return 0; } @@ -6135,7 +6140,7 @@ int built_in_chipset_prefs (struct uae_prefs *p) p->cs_ksmirror_e0 = 0; break; case CP_CD32: // CD32 - p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = 1; + p->cs_cd32c2p = p->cs_cd32cd = p->cs_cd32nvram = true; p->cs_ksmirror_e0 = 0; p->cs_ksmirror_a8 = 1; p->cs_ciaoverlay = 0; diff --git a/custom.cpp b/custom.cpp index 74566725..78a19687 100644 --- a/custom.cpp +++ b/custom.cpp @@ -44,6 +44,7 @@ #endif #include "debug.h" #include "akiko.h" +#include "cd32_fmv.h" #include "cdtv.h" #if defined(ENFORCER) #include "enforcer.h" @@ -202,6 +203,7 @@ int firstblankedline; static int equ_vblank_endline = EQU_ENDLINE_PAL; static bool equ_vblank_toggle = true; double vblank_hz = VBLANK_HZ_PAL, fake_vblank_hz, vblank_hz_stored, vblank_hz_nom; +double hblank_hz; static float vblank_hz_lof, vblank_hz_shf, vblank_hz_lace; static int vblank_hz_mult, vblank_hz_state; static struct chipset_refresh *stored_chipset_refresh; @@ -3504,6 +3506,9 @@ int vsynctimebase_orig; void compute_vsynctime (void) { + double svpos = maxvpos_nom; + double shpos = maxhpos_short; + fake_vblank_hz = 0; vblank_hz_mult = 0; vblank_hz_state = 1; @@ -3529,21 +3534,20 @@ void compute_vsynctime (void) updatedisplayarea (); } #endif + if (islinetoggle ()) { + shpos += 0.5; + } + if (interlace_seen) { + svpos += 0.5; + } else if (lof_current) { + svpos += 1.0; + } if (currprefs.produce_sound > 1) { - double svpos = maxvpos_nom; - double shpos = maxhpos_short; - if (islinetoggle ()) { - shpos += 0.5; - } - if (interlace_seen) { - svpos += 0.5; - } else if (lof_current) { - svpos += 1.0; - } double clk = svpos * shpos * fake_vblank_hz; //write_log (_T("SNDRATE %.1f*%.1f*%.6f=%.6f\n"), svpos, shpos, fake_vblank_hz, clk); update_sound (clk); } + cd32_fmv_set_sync(svpos); } @@ -3770,12 +3774,14 @@ void compute_framesync (void) compute_vsynctime (); + hblank_hz = (double)(currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) / (maxhpos + (islinetoggle() ? 0.5 : 0)); + write_log (_T("%s mode%s%s V=%.4fHz H=%0.4fHz (%dx%d+%d) IDX=%d (%s) D=%d RTG=%d/%d\n"), isntsc ? _T("NTSC") : _T("PAL"), islace ? _T(" lace") : (lof_lace ? _T(" loflace") : _T("")), doublescan > 0 ? _T(" dblscan") : _T(""), vblank_hz, - (double)(currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) / (maxhpos + (islinetoggle () ? 0.5 : 0)), + hblank_hz, maxhpos, maxvpos, lof_store ? 1 : 0, cr ? cr->index : -1, cr != NULL && cr->label != NULL ? cr->label : _T(""), @@ -4611,6 +4617,7 @@ static void rethink_intreq (void) #endif #ifdef CD32 rethink_akiko (); + rethink_cd32fmv(); #endif rethink_gayle (); } @@ -7064,6 +7071,9 @@ static void vsync_handler_pre (void) #ifdef RETROPLATFORM rp_vsync (); #endif +#ifdef CD32 + cd32_fmv_vsync_handler(); +#endif if (!vsync_rendered) { frame_time_t start, end; @@ -7483,6 +7493,7 @@ static void hsync_handler_pre (bool onvsync) #endif #ifdef CD32 AKIKO_hsync_handler (); + cd32_fmv_hsync_handler(); #endif #ifdef CDTV CDTV_hsync_handler (); diff --git a/drawing.cpp b/drawing.cpp index 7456e8ca..e9a1d487 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -49,6 +49,7 @@ happening, all ports should restrict window widths to be multiples of 16 pixels. #include "statusline.h" #include "inputdevice.h" #include "debug.h" +#include "cd32_fmv.h" extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*); @@ -3125,6 +3126,16 @@ bool draw_frame (struct vidbuffer *vb) return true; } +static void setnativeposition(struct vidbuffer *vb) +{ + vb->inwidth = gfxvidinfo.drawbuffer.inwidth; + vb->inheight = gfxvidinfo.drawbuffer.inheight; + vb->inwidth2 = gfxvidinfo.drawbuffer.inwidth2; + vb->inheight2 = gfxvidinfo.drawbuffer.inheight2; + vb->outwidth = gfxvidinfo.drawbuffer.outwidth; + vb->outheight = gfxvidinfo.drawbuffer.outheight; +} + static void finish_drawing_frame (void) { int i; @@ -3172,14 +3183,8 @@ static void finish_drawing_frame (void) if (currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated) { if (emulate_specialmonitors (vb, &gfxvidinfo.tempbuffer)) { vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; - if (vb->nativepositioning) { - vb->inwidth = gfxvidinfo.drawbuffer.inwidth; - vb->inheight = gfxvidinfo.drawbuffer.inheight; - vb->inwidth2 = gfxvidinfo.drawbuffer.inwidth2; - vb->inheight2 = gfxvidinfo.drawbuffer.inheight2; - vb->outwidth = gfxvidinfo.drawbuffer.outwidth; - vb->outheight = gfxvidinfo.drawbuffer.outheight; - } + if (vb->nativepositioning) + setnativeposition(vb); gfxvidinfo.drawbuffer.tempbufferinuse = true; if (!specialmonitoron) compute_framesync (); @@ -3194,6 +3199,19 @@ static void finish_drawing_frame (void) } } + if (!currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated && currprefs.cs_cd32fmv) { + if (cd32_fmv_active) { + cd32_fmv_genlock(vb, &gfxvidinfo.tempbuffer); + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + setnativeposition(vb); + gfxvidinfo.drawbuffer.tempbufferinuse = true; + do_flush_screen(vb, 0, vb->outheight); + didflush = true; + } else { + gfxvidinfo.drawbuffer.tempbufferinuse = false; + } + } + if (!didflush) do_flush_screen (vb, first_drawn_line, last_drawn_line); } diff --git a/expansion.cpp b/expansion.cpp index 2c5edb0e..25d3dc5c 100644 --- a/expansion.cpp +++ b/expansion.cpp @@ -1520,15 +1520,11 @@ void expamem_reset (void) } #endif #ifdef CD32 - if (currprefs.cs_cd32cd && currprefs.fastmem_size == 0 && currprefs.chipmem_size <= 0x200000) { - int ids[] = { 23, -1 }; - struct romlist *rl = getromlistbyids (ids); - if (rl && !_tcscmp (rl->path, currprefs.cartfile)) { - card_flags[cardno] = 0; - card_name[cardno] = _T("CD32MPEG"); - card_init[cardno] = expamem_init_cd32fmv; - card_map[cardno++] = expamem_map_cd32fmv; - } + if (currprefs.cs_cd32cd && currprefs.fastmem_size == 0 && currprefs.chipmem_size <= 0x200000 && currprefs.cs_cd32fmv) { + card_flags[cardno] = 0; + card_name[cardno] = _T("CD32MPEG"); + card_init[cardno] = expamem_init_cd32fmv; + card_map[cardno++] = expamem_map_cd32fmv; } #endif #ifdef A2065 diff --git a/include/cd32_fmv.h b/include/cd32_fmv.h index 458f849d..3343ab7f 100644 --- a/include/cd32_fmv.h +++ b/include/cd32_fmv.h @@ -1,2 +1,15 @@ extern void cd32_fmv_init (uaecptr); +extern void cd32_fmv_reset(void); +extern void cd32_fmv_free(void); +extern void rethink_cd32fmv(void); +extern void cd32_fmv_hsync_handler(void); +extern void cd32_fmv_vsync_handler(void); + +extern void cd32_fmv_state(int state); +extern void cd32_fmv_new_image(int, int, uae_u8*); +extern void cd32_fmv_genlock(struct vidbuffer*, struct vidbuffer*); +extern void cd32_fmv_new_border_color(uae_u32); +extern void cd32_fmv_set_sync(double svpos); + +extern int cd32_fmv_active; diff --git a/include/custom.h b/include/custom.h index 660fba93..9e212ddb 100644 --- a/include/custom.h +++ b/include/custom.h @@ -128,6 +128,7 @@ extern int maxvpos, maxvpos_nom, maxvpos_display; extern int hsyncstartpos, hsyncendpos; extern int minfirstline, vblank_endline, numscrlines; extern double vblank_hz, fake_vblank_hz; +extern double hblank_hz; extern int vblank_skip, doublescan; extern bool programmedmode; diff --git a/include/options.h b/include/options.h index a8ce1e5f..2f522395 100644 --- a/include/options.h +++ b/include/options.h @@ -176,7 +176,7 @@ struct uaedev_config_data int unitnum; // scsi unit number (if tape currently) }; -enum { CP_GENERIC = 1, CP_CDTV, CP_CD32, CP_A500, CP_A500P, CP_A600, CP_A1000, +enum { CP_GENERIC = 1, CP_CDTV, CP_CD32, CP_CD32FMV, CP_A500, CP_A500P, CP_A600, CP_A1000, CP_A1200, CP_A2000, CP_A3000, CP_A3000T, CP_A4000, CP_A4000T }; #define IDE_A600A1200 1 @@ -420,6 +420,7 @@ struct uae_prefs { bool cs_cd32cd; bool cs_cd32c2p; bool cs_cd32nvram; + bool cs_cd32fmv; bool cs_cdtvcd; bool cs_cdtvram; int cs_cdtvcard; diff --git a/main.cpp b/main.cpp index 6484e86d..b886b577 100644 --- a/main.cpp +++ b/main.cpp @@ -38,6 +38,7 @@ #include "scsidev.h" #include "uaeserial.h" #include "akiko.h" +#include "cd32_fmv.h" #include "cdtv.h" #include "savestate.h" #include "filesys.h" @@ -205,9 +206,15 @@ void fixup_prefs_dimensions (struct uae_prefs *prefs) if (prefs->gf[i].gfx_filter == 0 && ((prefs->gf[i].gfx_filter_autoscale && !prefs->gfx_api) || (prefs->gfx_apmode[APMODE_NATIVE].gfx_vsyncmode))) { prefs->gf[i].gfx_filter = 1; } - if (i == 0 && prefs->gf[i].gfx_filter == 0 && prefs->monitoremu) { - error_log (_T("A2024 and Graffiti require at least null filter enabled.")); - prefs->gf[i].gfx_filter = 1; + if (i == 0) { + if (prefs->gf[i].gfx_filter == 0 && prefs->monitoremu) { + error_log(_T("A2024 and Graffiti require at least null filter enabled.")); + prefs->gf[i].gfx_filter = 1; + } + if (prefs->gf[i].gfx_filter == 0 && prefs->cs_cd32fmv) { + error_log(_T("CD32 MPEG module overlay support require at least null filter enabled.")); + prefs->gf[i].gfx_filter = 1; + } } } } @@ -962,6 +969,7 @@ void do_leave_program (void) #endif #ifdef CD32 akiko_free (); + cd32_fmv_free(); #endif if (! no_gui) gui_exit (); diff --git a/od-win32/mman.cpp b/od-win32/mman.cpp index 4fd0daa6..e3d3c71e 100644 --- a/od-win32/mman.cpp +++ b/od-win32/mman.cpp @@ -538,11 +538,17 @@ void *shmat (int shmid, void *shmaddr, int shmflg) shmaddr=natmem_offset + 0xf00000; got = TRUE; readonly = TRUE; - } else if(!_tcscmp (shmids[shmid].name, _T("rtarea"))) { - shmaddr=natmem_offset + rtarea_base; + } else if (!_tcscmp(shmids[shmid].name, _T("rtarea"))) { + shmaddr = natmem_offset + rtarea_base; got = TRUE; readonly = TRUE; readonlysize = RTAREA_TRAPS; + } else if (!_tcscmp(shmids[shmid].name, _T("fmv_rom"))) { + got = TRUE; + shmaddr = natmem_offset + 0x200000; + } else if (!_tcscmp(shmids[shmid].name, _T("fmv_ram"))) { + got = TRUE; + shmaddr = natmem_offset + 0x280000; } else if(!_tcscmp (shmids[shmid].name, _T("fast"))) { got = TRUE; if (size < 524288) { -- 2.47.3