ygv608.cpp: added CRTC function, moved irqs in handler callbacks [Angelo Salese]

This commit is contained in:
angelosa 2017-06-29 00:29:47 +02:00
parent d0aba57fba
commit 12dc9f81a6
4 changed files with 290 additions and 186 deletions

View File

@ -202,9 +202,6 @@ static ADDRESS_MAP_START( namcond1_map, AS_PROGRAM, 16, namcond1_state )
AM_RANGE(0x400000, 0x40ffff) AM_RAM AM_SHARE("shared_ram")
AM_RANGE(0x800000, 0x80000f) AM_DEVICE8("ygv608", ygv608_device, port_map, 0xff00)
AM_RANGE(0xa00000, 0xa00fff) AM_DEVREADWRITE8("at28c16", at28c16_device, read, write, 0xff00)
#ifdef MAME_DEBUG
AM_RANGE(0xb00000, 0xb00001) AM_DEVREAD("ygv608", ygv608_device, debug_trigger_r)
#endif
AM_RANGE(0xc3ff00, 0xc3ffff) AM_READWRITE(cuskey_r,cuskey_w)
ADDRESS_MAP_END
@ -216,9 +213,6 @@ static ADDRESS_MAP_START( abcheck_map, AS_PROGRAM, 16, namcond1_state )
AM_RANGE(0x780000, 0x780001) AM_READ(printer_r)
AM_RANGE(0x800000, 0x80000f) AM_DEVICE8("ygv608", ygv608_device, port_map, 0xff00)
AM_RANGE(0xa00000, 0xa00fff) AM_DEVREADWRITE8("at28c16", at28c16_device, read, write, 0xff00)
#ifdef MAME_DEBUG
AM_RANGE(0xb00000, 0xb00001) AM_DEVREAD("ygv608", ygv608_device, debug_trigger_r)
#endif
AM_RANGE(0xc3ff00, 0xc3ffff) AM_READWRITE(cuskey_r,cuskey_w)
ADDRESS_MAP_END
@ -335,19 +329,22 @@ INTERRUPT_GEN_MEMBER(namcond1_state::mcu_interrupt)
- The level 1 interrupt to the 68k has been measured at 60Hz.
*******************************************/
WRITE_LINE_MEMBER( namcond1_state::vblank_irq_w )
{
m_maincpu->set_input_line(1, state ? ASSERT_LINE : CLEAR_LINE);
}
WRITE_LINE_MEMBER( namcond1_state::raster_irq_w )
{
m_maincpu->set_input_line(2, state ? ASSERT_LINE : CLEAR_LINE);
}
static MACHINE_CONFIG_START( namcond1 )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", M68000, XTAL_49_152MHz/4)
MCFG_CPU_PROGRAM_MAP(namcond1_map)
MCFG_CPU_VBLANK_INT_DRIVER("screen", namcond1_state, irq1_line_hold)
// I've disabled this for now, I don't think it's correct, it breaks ncv2 'game options' in test
// mode (and could also be responsible for the random resets?)
// also, if you log the timing of it and the scanlines on which the interrupt fires, it doesn't
// seem correct for the intended purpose?
//MCFG_DEVICE_PERIODIC_INT_DEVICE("ygv608", ygv608_device, timed_interrupt, 1000)
// MCFG_CPU_VBLANK_INT_DRIVER("screen", namcond1_state, irq1_line_hold)
MCFG_CPU_ADD("mcu", H83002, XTAL_49_152MHz/3 )
MCFG_CPU_PROGRAM_MAP( nd1h8rwmap)
@ -357,12 +354,18 @@ static MACHINE_CONFIG_START( namcond1 )
MCFG_QUANTUM_TIME(attotime::from_hz(6000))
MCFG_YGV608_ADD("ygv608")
MCFG_YGV608_PALETTE("palette")
MCFG_YGV608_VBLANK_HANDLER(WRITELINE(namcond1_state, vblank_irq_w))
MCFG_YGV608_RASTER_HANDLER(WRITELINE(namcond1_state, raster_irq_w))
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60.0)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
MCFG_SCREEN_SIZE(288, 224) // maximum display resolution (512x512 in theory)
MCFG_SCREEN_VISIBLE_AREA(0, 287, 0, 223) // default visible area
/*
H 804 108 576 48 32
V 261 26 224 3 0
*/
MCFG_SCREEN_RAW_PARAMS( XTAL_49_152MHz/8, 804/2, 108/2, (108+576)/2, 261, 26, 26+224)
MCFG_SCREEN_UPDATE_DEVICE("ygv608", ygv608_device, update_screen)
MCFG_SCREEN_PALETTE("palette")
@ -379,14 +382,13 @@ static MACHINE_CONFIG_START( namcond1 )
MCFG_AT28C16_ADD( "at28c16", nullptr )
MCFG_YGV608_ADD("ygv608")
MCFG_YGV608_PALETTE("palette")
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( abcheck, namcond1 )
MCFG_CPU_REPLACE("maincpu", M68000, XTAL_49_152MHz/4)
MCFG_CPU_PROGRAM_MAP(abcheck_map)
MCFG_CPU_VBLANK_INT_DRIVER("screen", namcond1_state, irq1_line_hold)
// MCFG_CPU_VBLANK_INT_DRIVER("screen", namcond1_state, irq1_line_hold)
MCFG_NVRAM_ADD_0FILL("zpr1")
MCFG_NVRAM_ADD_0FILL("zpr2")

View File

@ -43,5 +43,7 @@ public:
virtual void machine_start() override;
virtual void machine_reset() override;
INTERRUPT_GEN_MEMBER(mcu_interrupt);
DECLARE_WRITE_LINE_MEMBER( vblank_irq_w );
DECLARE_WRITE_LINE_MEMBER( raster_irq_w );
INTERRUPT_GEN_MEMBER(mcu_interrupt);
};

View File

@ -361,7 +361,12 @@ GFXDECODE_END
*
***************************************/
// we use decimals here to match documentation
static ADDRESS_MAP_START( regs_map, AS_IO, 8, ygv608_device )
AM_RANGE(14, 14) AM_READWRITE(irq_mask_r,irq_mask_w)
AM_RANGE(15, 16) AM_READWRITE(irq_ctrl_r,irq_ctrl_w)
AM_RANGE(39, 46) AM_WRITE(crtc_w)
ADDRESS_MAP_END
/***************************************
@ -390,7 +395,9 @@ ygv608_device::ygv608_device( const machine_config &mconfig, const char *tag, de
: device_t(mconfig, YGV608, tag, owner, clock),
device_gfx_interface(mconfig, *this, GFXDECODE_NAME(ygv608)),
device_memory_interface(mconfig, *this),
m_io_space_config("io", ENDIANNESS_BIG, 8, 6, 0, *ADDRESS_MAP_NAME(regs_map))
m_io_space_config("io", ENDIANNESS_BIG, 8, 6, 0, *ADDRESS_MAP_NAME(regs_map)),
m_vblank_handler(*this),
m_raster_handler(*this)
{
}
@ -446,7 +453,14 @@ void ygv608_device::device_start()
m_tilemap_B = nullptr;
m_iospace = &space(AS_IO);
// TODO: tagging configuration
m_screen = downcast<screen_device *>(machine().device("screen"));
m_vblank_handler.resolve();
m_raster_handler.resolve();
m_vblank_timer = timer_alloc(VBLANK_TIMER);
m_raster_timer = timer_alloc(RASTER_TIMER);
register_state_save();
}
@ -460,42 +474,32 @@ const address_space_config *ygv608_device::memory_space_config(address_spacenum
return (spacenum == AS_IO) ? &m_io_space_config : nullptr;
}
void ygv608_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch(id)
{
case VBLANK_TIMER:
{
m_screen_status |= 8; // FV
if(m_vblank_irq_mask == true)
m_vblank_handler(ASSERT_LINE);
break;
}
case RASTER_TIMER:
{
m_screen_status |= 0x10; // FP
if(m_raster_irq_mask == true)
m_raster_handler(ASSERT_LINE);
}
}
}
void ygv608_device::set_gfxbank(uint8_t gfxbank)
{
m_namcond1_gfxbank = gfxbank;
}
/* interrupt generated every 1ms second */
INTERRUPT_GEN_MEMBER(ygv608_device::timed_interrupt )
{
/*
this is not quite generic, because we trigger a 68k interrupt
- if this chip is ever used by another driver, we should make
this more generic - or move it into the machine driver
*/
static int timer = 0;
if( ++timer == 1000 )
timer = 0;
/* once every 60Hz, set the vertical border interval start flag */
if( ( timer % (1000/60) ) == 0 )
{
m_ports.s.p6 |= p6_fv;
if (m_regs.s.r14 & r14_iev)
device.execute().set_input_line(2, HOLD_LINE);
}
/* once every 60Hz, set the position detection flag (somewhere) */
else if( ( timer % (1000/60) ) == 7 )
{
m_ports.s.p6 |= p6_fp;
if (m_regs.s.r14 & r14_iep)
device.execute().set_input_line(2, HOLD_LINE);
}
}
TILEMAP_MAPPER_MEMBER( ygv608_device::get_tile_offset )
@ -1138,13 +1142,6 @@ uint32_t ygv608_device::update_screen(screen_device &screen, bitmap_ind16 &bitma
if( m_screen_resize )
{
#ifdef _ENABLE_SCREEN_RESIZE
// hdw should be scaled by 16, not 8
// - is it something to do with double dot-clocks???
screen.set_visible_area(0, ((int)(m_regs.s.hdw)<<3/*4*/)-1,
0, ((int)(m_regs.s.vdw)<<3)-1 );
#endif
m_work_bitmap.resize(screen.width(), screen.height());
// reset resize flag
@ -1455,7 +1452,7 @@ READ8_MEMBER(ygv608_device::register_data_r)
***/
READ8_MEMBER( ygv608_device::status_port_r )
{
return (uint8_t)(m_ports.b[6]);
return m_screen_status;
}
// P#7R - system control port
@ -1628,7 +1625,11 @@ WRITE8_MEMBER( ygv608_device::register_select_w )
WRITE8_MEMBER( ygv608_device::status_port_w )
{
/* writing a '1' resets that bit */
m_ports.b[6] &= ~data;
m_screen_status &= ~data;
if(data & 8)
m_vblank_handler(0);
if(data & 0x10)
m_raster_handler(0);
}
// P#7W - system control port
@ -1729,30 +1730,166 @@ void ygv608_device::HandleRomTransfers(uint8_t type)
#endif
}
#if 0
void nvsram( offs_t offset, uint16_t data )
/***************************************
*
* Register Interface routines
*
****************************************/
// R#14R interrupt mask control
READ8_MEMBER( ygv608_device::irq_mask_r )
{
static int i = 0;
data = ( data >> 8 ) & 0xff;
if( 1 ) {
static char ascii[16];
if( i%16 == 0 )
logerror( "%04X: ", offset );
logerror( "%02X ", data );
ascii[i%16] = (data > 0x20) ? data : '.';
if( i%16 == 15 )
logerror( "| %-16.16s\n", ascii );
}
i++;
return (m_raster_irq_mask << 1) | (m_vblank_irq_mask << 0);
}
// R#14W interrupt mask control
WRITE8_MEMBER( ygv608_device::irq_mask_w )
{
m_vblank_irq_mask = BIT(data, 0);
m_raster_irq_mask = BIT(data, 1);
}
// R#15R / R#16R raster interrupt control
READ8_MEMBER( ygv608_device::irq_ctrl_r )
{
uint8_t res;
if(offset == 0) // R#15
res = m_raster_irq_vpos & 0xff;
else // R#16
{
res = (m_raster_irq_mode << 7);
res|= (BIT(m_raster_irq_vpos, 8) << 6);
res|= (m_raster_irq_hpos / 32) & 0x1f;
}
return res;
}
// R#15W / R#16W raster interrupt control
WRITE8_MEMBER( ygv608_device::irq_ctrl_w )
{
if(offset == 0) // R#15
{
m_raster_irq_vpos &= ~0xff;
m_raster_irq_vpos |= data & 0xff;
}
else // R#16
{
m_raster_irq_mode = BIT(data,7);
m_raster_irq_vpos &= ~0x100;
m_raster_irq_vpos |= BIT(data,6) << 8;
m_raster_irq_hpos = (data & 0x1f) * 32;
}
}
// R#39W - R#46W display scan control write
WRITE8_MEMBER( ygv608_device::crtc_w )
{
//printf("[%d] <- %02x\n",offset+39,data);
switch(offset+39)
{
case 39:
{
m_crtc.display_hsync = ((data >> 5) & 7) * 16;
m_crtc.border_width = (data & 0x1f) * 16;
break;
}
case 40:
{
m_crtc.htotal &= ~0x600;
m_crtc.htotal |= (data & 0xc0) << 3;
m_crtc.display_width = (data & 0x3f) * 16;
break;
}
case 41:
{
m_crtc.display_hstart &= ~0x1fe;
m_crtc.display_hstart |= (data & 0xff) << 1;
break;
}
case 42:
{
m_crtc.htotal &= ~0x1fe;
m_crtc.htotal |= (data & 0xff) << 1;
printf("H %d %d %d %d %d\n",m_crtc.htotal,m_crtc.display_hstart,m_crtc.display_width,m_crtc.display_hsync,m_crtc.border_width);
break;
}
case 43:
{
m_crtc.display_vsync = (data >> 5) & 7;
m_crtc.border_height = (data & 0x1f) * 8;
break;
}
case 44:
{
// TODO: VSLS, bit 6
m_crtc.display_height = (data & 0x3f) * 8;
break;
}
case 45:
{
m_crtc.vtotal &= ~0x100;
m_crtc.vtotal |= BIT(data,7) << 8;
// TODO: TRES, bit 6
m_crtc.display_vstart = data & 0x3f;
break;
}
case 46:
{
m_crtc.vtotal &= ~0xff;
m_crtc.vtotal |= data & 0xff;
// TODO: call it for all mods in the CRTC
screen_configure();
//printf("V %d %d %d %d %d\n",m_crtc.vtotal,m_crtc.display_vstart,m_crtc.display_height,m_crtc.display_vsync,m_crtc.border_height);
break;
}
}
}
// TODO: all horizontal values needs to be divided by 2, presumably some other register?
// TODO: h/vstart not taken into account (needs video mods)
void ygv608_device::screen_configure()
{
// int display_hend = (m_crtc.display_hstart + (m_crtc.display_width / 2)) - 1;
int display_hend = (m_crtc.display_width / 2) - 1;
// int display_vend = (m_crtc.display_vstart + m_crtc.display_height) - 1;
int display_vend = (m_crtc.display_height) - 1;
//rectangle visarea(m_crtc.display_hstart, display_hend, m_crtc.display_vstart, display_vend);
rectangle visarea(0, display_hend, 0, display_vend);
attoseconds_t period = HZ_TO_ATTOSECONDS(m_screen->clock()) * m_crtc.vtotal * (m_crtc.htotal / 2);
m_screen->configure(m_crtc.htotal / 2, m_crtc.vtotal, visarea, period );
// reset vblank timer
m_vblank_timer->reset();
//m_vblank_timer->adjust(m_screen->time_until_pos(m_crtc.display_vstart+m_crtc.display_height,0), 0, m_screen->frame_period());
m_vblank_timer->adjust(m_screen->time_until_pos(m_crtc.display_height,0), 0, m_screen->frame_period());
}
#endif
// Set any "short-cut" variables before we update the YGV608 registers
// - these are used only in optimisation of the emulation
void ygv608_device::SetPreShortcuts( int reg, int data )
{
switch( reg ) {
@ -1937,106 +2074,10 @@ void ygv608_device::SetPostShortcuts(int reg )
}
/*
* The rest of this stuff is for debugging only!
*/
//#define SHOW_SOURCE_MODE
#if 0
void dump_block( char *name, uint8_t *block, int len )
{
int i;
logerror( "uint8_t %s[] = {\n", name );
for( i=0; i<len; i++ ) {
if( i%8 == 0 )
logerror( " " );
logerror( "0x%02X, ", block[i] );
if( i%8 == 7 )
logerror( "\n" );
}
logerror( "};\n" );
}
#endif
READ16_MEMBER( ygv608_device::debug_trigger_r )
{
static int oneshot = 0;
#ifndef SHOW_SOURCE_MODE
int i;
#endif
char ascii[16];
if( oneshot )
return( 0 );
oneshot = 1;
ShowYGV608Registers();
#ifdef SHOW_SOURCE_MODE
#if 0
dump_block( "ygv608_regs",
(uint8_t *)m_regs.b,
64 );
dump_block( "ygv608_pnt",
(uint8_t *)m_pattern_name_table,
4096 );
dump_block( "ygv608_sat",
(uint8_t *)m_sprite_attribute_table.b,
256 );
dump_block( "ygv608_sdt",
(uint8_t *)m_scroll_data_table,
512 );
dump_block( "ygv608_cp",
(uint8_t *)m_colour_palette,
768 );
#endif
#else
/*
* Dump pattern name table ram
*/
#if 1
logerror( "Pattern Name Table\n" );
for( i=0; i<4096; i++ ) {
if( i % 16 == 0 )
logerror( "$%04X : ", i );
logerror( "%02X ", m_pattern_name_table[i] );
if( m_pattern_name_table[i] >= 0x20)
ascii[i%16] = m_pattern_name_table[i];
else
ascii[i%16] = '.';
if( i % 16 == 15 )
logerror( " | %-16.16s\n", ascii );
}
logerror( "\n" );
#endif
/*
* Dump scroll table ram
*/
logerror( "Scroll Table\n" );
for( i=0; i<256; i++ ) {
if( i % 16 == 0 )
logerror( "$%04X : ", i );
logerror( "%02X ", m_scroll_data_table[0][i] );
if( m_scroll_data_table[0][i] >= 0x20 )
ascii[i%16] = m_scroll_data_table[0][i];
else
ascii[i%16] = '.';
if( i % 16 == 15 )
logerror( " | %-16.16s\n", ascii );
}
logerror( "\n" );
#endif
return( 0 );
}
void ygv608_device::ShowYGV608Registers()
{

View File

@ -1,15 +1,17 @@
// license:BSD-3-Clause
// copyright-holders:Mark McDougall
/*
* Yamaha YGV608 - PVDC2 Pattern mode Video Display Controller 2
* - Mark McDougall
*/
#ifndef MAME_VIDEO_YGV608_H
#define MAME_VIDEO_YGV608_H
#pragma once
#include "tilemap.h"
/*
* Yamaha YGV608 - PVDC2 Pattern mode Video Display Controller 2
* - Mark McDougall
*/
#include "screen.h"
class ygv608_device : public device_t,
public device_gfx_interface,
@ -21,6 +23,7 @@ public:
DECLARE_ADDRESS_MAP(port_map, 8);
// ports section
DECLARE_READ8_MEMBER(pattern_name_table_r);
DECLARE_READ8_MEMBER(sprite_data_r);
DECLARE_READ8_MEMBER(scroll_data_r);
@ -38,21 +41,35 @@ public:
DECLARE_WRITE8_MEMBER(status_port_w);
DECLARE_WRITE8_MEMBER(system_control_w);
// register section
DECLARE_READ8_MEMBER(irq_mask_r);
DECLARE_WRITE8_MEMBER(irq_mask_w);
DECLARE_READ8_MEMBER(irq_ctrl_r);
DECLARE_WRITE8_MEMBER(irq_ctrl_w);
DECLARE_WRITE8_MEMBER(crtc_w);
// TODO: is this even a real connection?
void set_gfxbank(uint8_t gfxbank);
uint32_t update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER( timed_interrupt );
// to be removed
DECLARE_READ16_MEMBER( debug_trigger_r );
template <class Object> static devcb_base &static_set_vblank_callback(device_t &device, Object &&cb)
{
return downcast<ygv608_device &>(device).m_vblank_handler.set_callback(std::forward<Object>(cb));
}
template <class Object> static devcb_base &static_set_raster_callback(device_t &device, Object &&cb)
{
return downcast<ygv608_device &>(device).m_raster_handler.set_callback(std::forward<Object>(cb));
}
protected:
// device-level overrides
virtual void device_start() override;
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_IO) const override;
void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
address_space *m_iospace;
private:
const address_space_config m_io_space_config;
@ -226,7 +243,42 @@ private:
// new variable handling starts here
uint8_t m_register_address; /**< RN: Register address select */
bool m_register_autoinc_r; /**< RRAI: Register address auto-increment on read */
bool m_register_autoinc_w; /**< RWAI: Register address auto-increment on write */
bool m_register_autoinc_w; /**< RWAI: Register address auto-increment on write */
uint8_t m_screen_status; /**< CD: status port r/w */
bool m_raster_irq_mask; /**< IEP: raster irq mask (INT1 occurs if 1) */
bool m_vblank_irq_mask; /**< IEV: vblank irq mask (INT0 occurs if 1) */
int m_raster_irq_hpos; /**< IH: horizontal position where raster irq occurs x 32 */
int m_raster_irq_vpos; /**< IV: vertical position where raster irq occurs */
bool m_raster_irq_mode; /**< FPM: if 1 vertical position becomes invalid for raster irqs (irqs occur for every line) */
// screen section
devcb_write_line m_vblank_handler;
devcb_write_line m_raster_handler;
screen_device *m_screen;
emu_timer *m_vblank_timer;
emu_timer *m_raster_timer;
enum
{
VBLANK_TIMER,
RASTER_TIMER
};
struct {
int htotal; /**< HTL: horizontal total number of dots x 2 */
int vtotal; /**< VTL: vertical total number of lines x 1 */
int display_hstart; /**< HDS: horizontal display starting position x 2*/
int display_vstart; /**< VDS: vertical display starting position x 1 */
int display_width; /**< HDW: horizontal display size x 16 */
int display_height; /**< VDW: vertical display size x 8 */
int display_hsync; /**< HSW: horizontal sync signal x 16 */
int display_vsync; /**< VSW: vertical sync signal x 1 */
int border_width; /**< HBW: horizontal border size x 16 */
int border_height; /**< VBW: vertical border size x 8 */
}m_crtc;
void screen_configure();
};
// device type definition
@ -243,4 +295,11 @@ DECLARE_DEVICE_TYPE(YGV608, ygv608_device)
#define MCFG_YGV608_PALETTE(_palette_tag) \
MCFG_GFX_PALETTE(_palette_tag)
#define MCFG_YGV608_VBLANK_HANDLER( _intcallb ) \
devcb = &ygv608_device::static_set_vblank_callback( *device, DEVCB_##_intcallb );
#define MCFG_YGV608_RASTER_HANDLER( _intcallb ) \
devcb = &ygv608_device::static_set_raster_callback( *device, DEVCB_##_intcallb );
#endif