*
* CD32 FMV cartridge
*
-* Copyright 2008-2010 Toni Wilen
+* Copyright 2008-2014 Toni Wilen
*
*/
#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);
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
{
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
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);
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
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
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);
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();
}