-mcd212: Various accuracy and timing improvements. [Ryan Holtz] (#9123)

* Added wait states on ROM and VRAM accesses.
  * Simplified pixel-duplication in 360/384-width modes.
  * Fixed DCA to process after VSR.
  * Switched to use raw parameters for screens.
  * Fixed some transparency-fill issues with disabled ICM/VSR.
This commit is contained in:
MooglyGuy 2022-01-13 02:37:27 +01:00 committed by GitHub
parent db8b82e60f
commit 255e3d6f3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 530 additions and 420 deletions

View File

@ -3,8 +3,8 @@
/******************************************************************************
Philips CD-I-based games
------------------------
Philips CD-i consoles and games
-------------------------------
Preliminary MAME driver by Ryan Holtz
Help provided by CD-i Fan
@ -30,14 +30,18 @@ STATUS:
* Philips IMS66490, "CDIC" ADPCM decoder
* PC85010 DSP
Quizard:
- Quizard 3 and 4 fail when going in-game, presumably due to CD-i emulation
faults.
TODO:
- Screen clocks are a hack right now; they should be exactly CLOCK_A/2. However, the
MCD-212 documentation states in both tables and timing diagrams that vertical retrace
has an additional half-line even in non-interlaced mode, which cannot be represented
in the current screen-timing framework. The input clock has been adjusted downward
to factor out this half-line, resulting in the expected 50Hz exactly in PAL mode.
- Proper abstraction of the 68070's internal devices (UART, DMA, Timers, etc.)
- Mono-I: Full emulation of the CDIC, as well as the SERVO and SLAVE MCUs
- Mono-II: SERVO and SLAVE I/O device hookup
- Mono-II: DSP56k hookup
@ -81,8 +85,8 @@ TODO:
void cdi_state::cdimono1_mem(address_map &map)
{
map(0x000000, 0xffffff).rw(FUNC(cdi_state::bus_error_r), FUNC(cdi_state::bus_error_w));
map(0x000000, 0x07ffff).ram().share("mcd212:planea");
map(0x200000, 0x27ffff).ram().share("mcd212:planeb");
map(0x000000, 0x07ffff).rw(FUNC(cdi_state::plane_r<0>), FUNC(cdi_state::plane_w<0>)).share("plane0");
map(0x200000, 0x27ffff).rw(FUNC(cdi_state::plane_r<1>), FUNC(cdi_state::plane_w<1>)).share("plane1");
map(0x300000, 0x303bff).rw(m_cdic, FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w));
#if ENABLE_UART_PRINTING
map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable));
@ -91,7 +95,7 @@ void cdi_state::cdimono1_mem(address_map &map)
map(0x310000, 0x317fff).rw(m_slave_hle, FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w));
map(0x318000, 0x31ffff).noprw();
map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */
map(0x400000, 0x47ffff).rom().region("maincpu", 0);
map(0x400000, 0x47ffff).r(FUNC(cdi_state::main_rom_r));
map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map));
map(0x500000, 0x57ffff).ram();
map(0xd00000, 0xdfffff).ram(); // DVC RAM block 1
@ -101,22 +105,21 @@ void cdi_state::cdimono1_mem(address_map &map)
void cdi_state::cdimono2_mem(address_map &map)
{
map(0x000000, 0x07ffff).ram().share("mcd212:planea");
map(0x200000, 0x27ffff).ram().share("mcd212:planeb");
map(0x000000, 0x07ffff).ram().share("plane0");
map(0x200000, 0x27ffff).ram().share("plane1");
#if ENABLE_UART_PRINTING
map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable));
#endif
map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */
map(0x400000, 0x47ffff).rom().region("maincpu", 0);
map(0x400000, 0x47ffff).r(FUNC(cdi_state::main_rom_r));
map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map));
}
void cdi_state::cdi910_mem(address_map &map)
{
map(0x000000, 0x07ffff).ram().share("mcd212:planea");
map(0x000000, 0x07ffff).ram().share("plane0");
map(0x180000, 0x1fffff).rom().region("maincpu", 0); // boot vectors point here
map(0x200000, 0x27ffff).ram().share("mcd212:planeb");
map(0x200000, 0x27ffff).ram().share("plane1");
#if ENABLE_UART_PRINTING
map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable));
#endif
@ -174,8 +177,8 @@ INPUT_PORTS_END
void cdi_state::machine_reset()
{
uint16_t *src = (uint16_t*)memregion("maincpu")->base();
uint16_t *dst = m_planea;
uint16_t *src = &m_main_rom[0];
uint16_t *dst = &m_plane_ram[0][0];
memcpy(dst, src, 0x8);
}
@ -194,6 +197,31 @@ void quizard_state::machine_reset()
}
/***************************
* Wait-State Handling *
***************************/
template<int Channel>
uint16_t cdi_state::plane_r(offs_t offset, uint16_t mem_mask)
{
m_maincpu->eat_cycles(m_mcd212->ram_dtack_cycle_count<Channel>());
return m_plane_ram[Channel][offset];
}
template<int Channel>
void cdi_state::plane_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
m_maincpu->eat_cycles(m_mcd212->ram_dtack_cycle_count<Channel>());
COMBINE_DATA(&m_plane_ram[Channel][offset]);
}
uint16_t cdi_state::main_rom_r(offs_t offset)
{
m_maincpu->eat_cycles(m_mcd212->rom_dtack_cycle_count());
return m_main_rom[offset];
}
/**********************
* BERR Handling *
**********************/
@ -393,18 +421,14 @@ void cdi_state::cdimono1_base(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdimono1_mem);
m_maincpu->iack4_callback().set(m_cdic, FUNC(cdicdic_device::intack_r));
MCD212(config, m_mcd212, CLOCK_A);
MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(50);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_raw(14976000, 960, 0, 768, 312, 32, 312);
screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
screen.set_size(384, 312);
screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution
screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(50);
@ -445,18 +469,14 @@ void cdi_state::cdimono2(machine_config &config)
SCC68070(config, m_maincpu, CLOCK_A);
m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdimono2_mem);
MCD212(config, m_mcd212, CLOCK_A);
MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_raw(14976000, 960, 0, 768, 312, 32, 312);
screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
screen.set_size(384, 312);
screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution
screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(60);
@ -493,18 +513,14 @@ void cdi_state::cdi910(machine_config &config)
SCC68070(config, m_maincpu, CLOCK_A);
m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdi910_mem);
MCD212(config, m_mcd212, CLOCK_A);
MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(50);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_raw(14976000, 960, 0, 768, 312, 32, 312);
screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
screen.set_size(384, 312);
screen.set_visarea(0, 384-1, 32, 312-1); // TODO: dynamic resolution
screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(60);

View File

@ -21,8 +21,9 @@ public:
cdi_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_main_rom(*this, "maincpu")
, m_lcd(*this, "lcd")
, m_planea(*this, "mcd212:planea")
, m_plane_ram(*this, "plane%u", 0U)
, m_slave_hle(*this, "slave_hle")
, m_servo(*this, "servo")
, m_slave(*this, "slave")
@ -42,6 +43,7 @@ protected:
void cdimono1_mem(address_map &map);
required_device<scc68070_device> m_maincpu;
required_region_ptr<uint16_t> m_main_rom;
optional_device<screen_device> m_lcd;
private:
@ -58,13 +60,18 @@ private:
void cdimono2_mem(address_map &map);
void cdi070_cpuspace(address_map &map);
template<int Channel> uint16_t plane_r(offs_t offset, uint16_t mem_mask = ~0);
template<int Channel> void plane_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t main_rom_r(offs_t offset);
uint16_t dvc_r(offs_t offset, uint16_t mem_mask = ~0);
void dvc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t bus_error_r(offs_t offset);
void bus_error_w(offs_t offset, uint16_t data);
required_shared_ptr<uint16_t> m_planea;
required_shared_ptr_array<uint16_t, 2> m_plane_ram;
optional_device<cdislave_hle_device> m_slave_hle;
optional_device<m68hc05c8_device> m_servo;
optional_device<m68hc05c8_device> m_slave;

File diff suppressed because it is too large Load Diff

View File

@ -35,21 +35,34 @@ class mcd212_device : public device_t,
public device_video_interface
{
public:
template <typename T, typename U>
mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&plane_a_tag, U &&plane_b_tag)
: mcd212_device(mconfig, tag, owner, clock)
{
m_planea.set_tag(std::forward<T>(plane_a_tag));
m_planeb.set_tag(std::forward<U>(plane_b_tag));
}
mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto int_callback() { return m_int_callback.bind(); }
DECLARE_WRITE_LINE_MEMBER(screen_vblank);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void map(address_map &map);
template <int Channel> int ram_dtack_cycle_count();
int rom_dtack_cycle_count();
protected:
// device-level overrides
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
TIMER_CALLBACK_MEMBER(ica_tick);
TIMER_CALLBACK_MEMBER(dca_tick);
uint8_t csr1_r();
void csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dcr1_r(offs_t offset, uint16_t mem_mask = ~0);
@ -83,19 +96,18 @@ protected:
CURCNT_BLKC = 0x400000, // Blink type
CURCNT_EN = 0x800000, // Cursor enable
ICM_CS = 0x400000, // CLUT select
ICM_NR = 0x080000, // Number of region flags
ICM_NR_BIT = 19,
ICM_EV = 0x040000, // External video
ICM_MODE2 = 0x000f00, // Plane 2
ICM_MODE2_SHIFT = 8,
ICM_MODE1 = 0x00000f, // Plane 1
ICM_MODE1_SHIFT = 0,
ICM_MODE2 = 0x000f00, // Plane 2
ICM_MODE2_SHIFT = 8,
ICM_EV = 0x040000, // External video
ICM_NR = 0x080000, // Number of region flags
ICM_NR_BIT = 19,
ICM_CS = 0x400000, // CLUT select
TCR_DISABLE_MX = 0x800000, // Mix disable
TCR_TA = 0x00000f, // Plane A
TCR_TB = 0x000f00, // Plane B
TCR_TB_SHIFT = 8,
TCR_TA = 0x00000f, // Plane A
TCR_COND_1 = 0x0, // Transparent if: Always (Plane Disabled)
TCR_COND_KEY_1 = 0x1, // Transparent if: Color Key = True
TCR_COND_XLU_1 = 0x2, // Transparent if: Transparency Bit = 1
@ -112,6 +124,7 @@ protected:
TCR_COND_RF0KEY_0 = 0xd, // Transparent if: Region Flag 0 = False && Color Key = False
TCR_COND_RF1KEY_0 = 0xe, // Transparent if: Region Flag 1 = False && Color Key = False
TCR_COND_UNUSED1 = 0xf, // Unused
TCR_DISABLE_MX = 0x800000, // Mix disable
POR_AB = 0, // Plane A in front of Plane B
POR_BA = 1, // Plane B in front of Plane A
@ -123,32 +136,47 @@ protected:
RC_OP = 0xf00000, // Operation
RC_OP_SHIFT = 20,
CSR1W_ST = 0x0002, // Standard
CSR1W_BE = 0x0001, // Bus Error
CSR1R_PA = 0x20, // Parity
CSR1R_DA = 0x80, // Display Active
CSR2R_IT1 = 0x0004, // Interrupt 1
CSR2R_IT2 = 0x0002, // Interrupt 2
CSR2R_BE = 0x0001, // Bus Error
CSR1W_BE = 0x0001, // Bus Error
CSR1W_ST_BIT = 1, // Standard
CSR1W_DD_BIT = 3,
CSR1W_DD2 = 0x0300, // /DTACK Delay
CSR1W_DD2_SHIFT = 8,
CSR1W_DI1_BIT = 15,
DCR_DE = 0x8000, // Display Enable
DCR_CF = 0x4000, // Crystal Frequency
DCR_FD = 0x2000, // Frame Duration
DCR_SM = 0x1000, // Scan Mode
DCR_CM = 0x0800, // Color Mode Ch.1/2
DCR_ICA = 0x0200, // ICA Enable Ch.1/2
DCR_DCA = 0x0100, // DCA Enable Ch.1/2
CSR2R_BE = 0x0001, // Bus Error
CSR2R_IT2 = 0x0002, // Interrupt 2
CSR2R_IT1 = 0x0004, // Interrupt 1
DDR_FT = 0x0300, // Display File Type
DDR_FT_BMP = 0x0000, // Bitmap
DDR_FT_BMP2 = 0x0100, // Bitmap (alt.)
DDR_FT_RLE = 0x0200, // Run-Length Encoded
DDR_FT_MOSAIC = 0x0300, // Mosaic
DDR_MT = 0x0c00, // Mosaic File Type
DDR_MT_2 = 0x0000, // 2x1
DDR_MT_4 = 0x0400, // 4x1
DDR_MT_8 = 0x0800, // 8x1
DDR_MT_16 = 0x0c00, // 16x1
DDR_MT_SHIFT = 10
DCR_DCA_BIT = 8, // DCA Enable Ch.1/2
DCR_ICA_BIT = 9, // ICA Enable Ch.1/2
DCR_CM_BIT = 11, // Color Mode Ch.1/2
DCR_SM_BIT = 12, // Scan Mode
DCR_FD_BIT = 13, // Frame Duration
DCR_CF_BIT = 14, // Crystal Frequency
DCR_DE_BIT = 15, // Display Enable
DDR_MT = 0x0c00, // Mosaic File Type
DDR_MT_2 = 0x0000, // 2x1
DDR_MT_4 = 0x0400, // 4x1
DDR_MT_8 = 0x0800, // 8x1
DDR_MT_16 = 0x0c00, // 16x1
DDR_MT_SHIFT = 10,
DDR_FT = 0x0300, // Display File Type
DDR_FT_BMP = 0x0000, // Bitmap
DDR_FT_BMP2 = 0x0100, // Bitmap (alt.)
DDR_FT_RLE = 0x0200, // Run-Length Encoded
DDR_FT_MOSAIC = 0x0300, // Mosaic
ICM_OFF = 0x0,
ICM_CLUT8 = 0x1,
ICM_RGB555 = 0x2,
ICM_CLUT7 = 0x3,
ICM_CLUT77 = 0x4,
ICM_DYUV = 0x5,
ICM_CLUT4 = 0xb
};
uint8_t m_csrr[2];
@ -207,6 +235,8 @@ protected:
bool m_region_flag[2][768];
int m_ica_height;
int m_total_height;
emu_timer *m_ica_timer;
emu_timer *m_dca_timer;
static const uint32_t s_4bpp_color[16];
@ -214,8 +244,9 @@ protected:
uint8_t get_region_op(const uint32_t region_idx);
void update_region_arrays();
void update_visible_area();
uint32_t get_screen_width();
int get_screen_width();
int get_border_width();
template <int Channel> int get_plane_width();
template <int Channel> void set_vsr(uint32_t value);
template <int Channel> uint32_t get_vsr();
@ -239,7 +270,6 @@ protected:
template <bool MosaicA, bool MosaicB, bool OrderAB> void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out);
void draw_cursor(uint32_t *scanline);
void draw_scanline(bitmap_rgb32 &bitmap);
};
// device type definition