// license:LGPL-2.1+ // copyright-holders:Angelo Salese /*************************************************************************************************************************** Konami 053252 chip emulation, codenamed "CCU" device emulation by Angelo Salese, based off notes by Olivier Galibert ============================================================================================================================ left res = current in game, right res = computed hexion: 02 FF 00 4D 00 73 00 00 01 1F 05 0E B7 7C 00 00 512x256 ~ 512x256 <- writes to e and f regs, in an irq ack fashion overdriv: 01 7F 00 22 00 0D 00 03 01 07 10 0F 73 00 00 00 304x256 ~ 305x224 esckids: 01 7F 00 12 00 0D 00 01 01 07 08 07 73 00 00 00 304x224 ~ 321x240 rollerg: 01 7F 00 23 00 1D 02 00 01 07 10 0F 73 00 02 00 288x224 ~ 288x224 <- writes to 6 and e regs, in an irq ack fashion gaiapols: 01 FB 00 19 00 37 00 00 01 06 10 0E 75 00 D1 00 376x224 ~ 380x224 mmaulers: 01 7F 00 19 00 27 00 00 01 07 10 0F 73 00 00 00 288x224 ~ 288x224 mystwarr: 01 7F 00 12 00 2E 00 00 01 07 11 0E 73 00 00 00 288x224 ~ 288x224 metamrph: 01 7F 00 11 00 27 01 00 01 07 10 0F 74 00 00 00 288x224 ~ 288x224 viostorm: 01 FF 00 16 00 39 00 00 01 07 11 0E 75 00 00 00 384x224 ~ 385x224 mtlchamp: 01 FF 00 21 00 37 00 00 01 07 11 0E 74 00 00 00 384x224 ~ 384x224 dbz: 01 FF 00 21 00 37 00 00 01 20 0C 0E 54 00 00 00 384x256 ~ 384x256 dbz2: 01 FF 00 21 00 37 00 00 01 20 0C 0E 54 00 00 00 384x256 ~ 384x256 xexex: 01 FF 00 21 00 37 01 00 00 20 0C 0E 54 00 00 00 384x256 ~ 384x256 (*) (all konamigx, cowboys of moo mesa, run & gun, dj main) (*) hcount total 512 (0x200), hdisp 384 (0x180), vcount total 289 (0x121), vdisp 256 (0x100) Definitions from GX, look similar, all values big-endian, write-only: 0-1: bits 9-0: HC - Total horizontal count (-1) Hres ~ (HC+1) - HFP - HBP - 8*(HSW+1) 2-3: bits 8-0: HFP - HBlank front porch 4-5: bits 8-0: HBP - HBlank back porch 6 : bits 7-0: INT1EN 7 : bits 7-0: INT2EN 8-9: bits 8-0: VC - Total vertical count (-1) Vres ~ (VC+1) - VFP - (VBP+1) - (VSW+1) a : bits 7-0: VFP - VBlank front porch b : bits 7-0: VBP - VBlank back porch (-1) (?) c : bits 7-4: VSW - V-Sync Width c : bits 3-0: HSW - H-Sync Width d : bits 7-0: INT-TIME e : bits 7-0: INT1ACK f : bits 7-0: INT2ACK Read-only: e-f: bits 8-0: VCT TODO: - xexex sets up 0x20 as the VC? default value? - xexex layers are offsetted if you try to use the CCU - according to p.14-15 both HBP and VBP have +1 added, but to get correct visible areas you have to add it only to VBP - understand how to interpret the back / front porch values, and remove the offset x/y hack - dual screen support (for Konami GX types 3/4) - viostorm and dbz reads the VCT port, but their usage is a side effect to send an irq ack thru the same port: i.e. first one uses move.b $26001d.l, $26001d.l, second one clr.b - le2 sets int-time but never ever enables hblank irq? ***************************************************************************************************************************/ #include "emu.h" #include "k053252.h" #include "multibyte.h" DEFINE_DEVICE_TYPE(K053252, k053252_device, "k053252", "K053252 Timing/Interrupt Controller") k053252_device::k053252_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, K053252, tag, owner, clock) , device_video_interface(mconfig, *this) , m_int1_en_cb(*this) , m_int2_en_cb(*this) , m_int1_ack_cb(*this) , m_int2_ack_cb(*this) , m_int_time_cb(*this) , m_offsx(0) , m_offsy(0) , m_slave_screen(*this, finder_base::DUMMY_TAG) // ugly, needed to work with the rungun etc. video demux board { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void k053252_device::device_start() { save_item(NAME(m_regs)); save_item(NAME(m_hc)); save_item(NAME(m_hfp)); save_item(NAME(m_hbp)); save_item(NAME(m_vc)); save_item(NAME(m_vfp)); save_item(NAME(m_vbp)); save_item(NAME(m_vsw)); save_item(NAME(m_hsw)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void k053252_device::device_reset() { int i; for (i = 0; i < 16; i++) m_regs[i] = 0; m_regs[0x08] = 1; // Xexex apparently does a wrong assignment for VC (sets up the INT enable register instead) reset_internal_state(); } void k053252_device::reset_internal_state() { m_hc=0; m_hfp=0; m_hbp=0; m_vc=0; m_vfp=0; m_vbp=0; m_vsw=0; m_hsw=0; } /***************************************************************************** DEVICE HANDLERS *****************************************************************************/ uint8_t k053252_device::read(offs_t offset) { //TODO: debugger_access() switch(offset) { /* VCT read-back */ // TODO: correct? case 0x0e: return ((screen().vpos()-m_vc) >> 8) & 1; case 0x0f: return (screen().vpos()-m_vc) & 0xff; default: //popmessage("Warning: k053252 read %02x, contact MAMEdev",offset); break; } return m_regs[offset]; } void k053252_device::res_change() { if(m_hc && m_vc && m_hbp && m_hfp && m_vbp && m_vfp && m_hsw && m_vsw) //safety checks { rectangle visarea; //(HC+1) - HFP - HBP - 8*(HSW+1) //VC - VFP - VBP - (VSW+1) attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * (m_hc) * m_vc; visarea.min_x = m_offsx; visarea.min_y = m_offsy; visarea.max_x = m_offsx + m_hc - m_hfp - m_hbp - 8*(m_hsw) - 1; visarea.max_y = m_offsy + m_vc - m_vfp - m_vbp - (m_vsw) - 1; screen().configure(m_hc, m_vc, visarea, refresh); if (m_slave_screen.found()) m_slave_screen->configure(m_hc, m_vc, visarea, refresh); #if 0 attoseconds_t hsync = HZ_TO_ATTOSECONDS(clock()) * (m_hc); printf("H %d HFP %d HSW %d HBP %d\n",m_hc,m_hfp,m_hsw*8,m_hbp); printf("V %d VFP %d VSW %d VBP %d\n",m_vc,m_vfp,m_vsw,m_vbp); // L stands for Legacy ... printf("L %d %d\n",m_offsx,m_offsy); printf("Screen params: Clock: %u V-Sync %.2f H-Sync %.f\n",clock(),ATTOSECONDS_TO_HZ(refresh),ATTOSECONDS_TO_HZ(hsync)); printf("visible screen area: %d x %d\n\n",(visarea.max_x - visarea.min_x) + 1,(visarea.max_y - visarea.min_y) + 1); #endif } } void k053252_device::write(offs_t offset, uint8_t data) { m_regs[offset] = data; switch(offset) { case 0x00: case 0x01: m_hc = get_u16be(&m_regs[0])&0x03ff; m_hc++; logerror("%d (%04x) HC set\n",m_hc,m_hc); res_change(); break; case 0x02: case 0x03: m_hfp = get_u16be(&m_regs[2])&0x01ff; logerror("%d (%04x) HFP set\n",m_hfp,m_hfp); res_change(); break; case 0x04: case 0x05: m_hbp = get_u16be(&m_regs[4])&0x01ff; logerror("%d (%04x) HBP set\n",m_hbp,m_hbp); res_change(); break; case 0x06: m_int1_en_cb(data); break; case 0x07: m_int2_en_cb(data); break; case 0x08: case 0x09: m_vc = get_u16be(&m_regs[8])&0x01ff; m_vc++; logerror("%d (%04x) VC set\n",m_vc,m_vc); res_change(); break; case 0x0a: m_vfp = (m_regs[0x0a]&0xff); logerror("%d (%04x) VFP set\n",m_vfp,m_vfp); res_change(); break; case 0x0b: m_vbp = (m_regs[0x0b]&0xff); m_vbp++; logerror("%d (%04x) VBP set\n",m_vbp,m_vbp); res_change(); break; case 0x0c: m_vsw = ((m_regs[0x0c]&0xf0) >> 4) + 1; m_hsw = ((m_regs[0x0c]&0x0f) >> 0) + 1; logerror("%02x VSW / %02x HSW set\n",m_vsw,m_hsw); res_change(); break; case 0x0d: m_int_time_cb(data); break; case 0x0e: m_int1_ack_cb(1); break; case 0x0f: m_int2_ack_cb(1); break; } }