diff options
Diffstat (limited to 'src/devices/machine/sega_scu.cpp')
-rw-r--r-- | src/devices/machine/sega_scu.cpp | 776 |
1 files changed, 776 insertions, 0 deletions
diff --git a/src/devices/machine/sega_scu.cpp b/src/devices/machine/sega_scu.cpp new file mode 100644 index 00000000000..91154a9f775 --- /dev/null +++ b/src/devices/machine/sega_scu.cpp @@ -0,0 +1,776 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + Sega System Control Unit (c) 1995 Sega + + TODO: + - make a screen_device subclass, add pixel timers & irq callbacks to it; + - A-Bus external interrupts; + - Pad signal (lightgun I presume); + - Improve DMA, use DRQ model and timers, make them subdevices? + (old DMA TODO) + - Remove CD transfer DMA hack (tied with CD block bug(s)?) + - Add timings(but how fast are each DMA?). + - Add level priority & DMA status register. + +***************************************************************************/ +/********************************************************************************** +SCU Register Table +offset,relative address +Registers are in long words. +=================================================================================== +0 0000 Level 0 DMA Set Register +1 0004 +2 0008 +3 000c +4 0010 +5 0014 +6 0018 +7 001c +8 0020 Level 1 DMA Set Register +9 0024 +10 0028 +11 002c +12 0030 +13 0034 +14 0038 +15 003c +16 0040 Level 2 DMA Set Register +17 0044 +18 0048 +19 004c +20 0050 +21 0054 +22 0058 +23 005c +24 0060 DMA Forced Stop +25 0064 +26 0068 +27 006c +28 0070 <Free> +29 0074 +30 0078 +31 007c DMA Status Register +32 0080 DSP Program Control Port +33 0084 DSP Program RAM Data Port +34 0088 DSP Data RAM Address Port +35 008c DSP Data RAM Data Port +36 0090 Timer 0 Compare Register +37 0094 Timer 1 Set Data Register +38 0098 Timer 1 Mode Register +39 009c <Free> +40 00a0 Interrupt Mask Register +41 00a4 Interrupt Status Register +42 00a8 A-Bus Interrupt Acknowledge +43 00ac <Free> +44 00b0 A-Bus Set Register +45 00b4 +46 00b8 A-Bus Refresh Register +47 00bc <Free> +48 00c0 +49 00c4 SCU SDRAM Select Register +50 00c8 SCU Version Register +51 00cc <Free> +52 00cf +=================================================================================== +DMA Status Register(32-bit): +xxxx xxxx x--- xx-- xx-- xx-- xx-- xx-- UNUSED +---- ---- -x-- ---- ---- ---- ---- ---- DMA DSP-Bus access +---- ---- --x- ---- ---- ---- ---- ---- DMA B-Bus access +---- ---- ---x ---- ---- ---- ---- ---- DMA A-Bus access +---- ---- ---- --x- ---- ---- ---- ---- DMA lv 1 interrupt +---- ---- ---- ---x ---- ---- ---- ---- DMA lv 0 interrupt +---- ---- ---- ---- --x- ---- ---- ---- DMA lv 2 in stand-by +---- ---- ---- ---- ---x ---- ---- ---- DMA lv 2 in operation +---- ---- ---- ---- ---- --x- ---- ---- DMA lv 1 in stand-by +---- ---- ---- ---- ---- ---x ---- ---- DMA lv 1 in operation +---- ---- ---- ---- ---- ---- --x- ---- DMA lv 0 in stand-by +---- ---- ---- ---- ---- ---- ---x ---- DMA lv 0 in operation +---- ---- ---- ---- ---- ---- ---- --x- DSP side DMA in stand-by +---- ---- ---- ---- ---- ---- ---- ---x DSP side DMA in operation + +**********************************************************************************/ + +#include "emu.h" +#include "sega_scu.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +DEFINE_DEVICE_TYPE(SEGA_SCU, sega_scu_device, "sega_scu", "Sega System Control Unit") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//AM_RANGE(0x0000, 0x0003) src +//AM_RANGE(0x0004, 0x0007) dst +//AM_RANGE(0x0008, 0x000b) size +//AM_RANGE(0x000c, 0x000f) src/dst add values +//AM_RANGE(0x0010, 0x0013) DMA enable +//AM_RANGE(0x0014, 0x0017) DMA start factor + +DEVICE_ADDRESS_MAP_START( regs_map, 32, sega_scu_device ) + AM_RANGE(0x0000, 0x0017) AM_READWRITE(dma_lv0_r,dma_lv0_w) + AM_RANGE(0x0020, 0x0037) AM_READWRITE(dma_lv1_r,dma_lv1_w) + AM_RANGE(0x0040, 0x0057) AM_READWRITE(dma_lv2_r,dma_lv2_w) + // Super Major League and Shin Megami Tensei - Akuma Zensho reads from there (undocumented), DMA status mirror? + AM_RANGE(0x005c, 0x005f) AM_READ(dma_status_r) +// AM_RANGE(0x0060, 0x0063) AM_WRITE(dma_force_stop_w) + AM_RANGE(0x007c, 0x007f) AM_READ(dma_status_r) + AM_RANGE(0x0080, 0x0083) AM_DEVREADWRITE("scudsp",scudsp_cpu_device, program_control_r,program_control_w) + AM_RANGE(0x0084, 0x0087) AM_DEVWRITE("scudsp", scudsp_cpu_device, program_w) + AM_RANGE(0x0088, 0x008b) AM_DEVWRITE("scudsp", scudsp_cpu_device, ram_address_control_w) + AM_RANGE(0x008c, 0x008f) AM_DEVREADWRITE("scudsp", scudsp_cpu_device, ram_address_r, ram_address_w) + AM_RANGE(0x0090, 0x0093) AM_WRITE(t0_compare_w) + AM_RANGE(0x0094, 0x0097) AM_WRITE(t1_setdata_w) + AM_RANGE(0x0098, 0x009b) AM_WRITE16(t1_mode_w,0x0000ffff) + AM_RANGE(0x00a0, 0x00a3) AM_READWRITE(irq_mask_r,irq_mask_w) + AM_RANGE(0x00a4, 0x00a7) AM_READWRITE(irq_status_r,irq_status_w) +// AM_RANGE(0x00a8, 0x00ab) AM_WRITE(abus_irqack_w) +// AM_RANGE(0x00b0, 0x00b7) AM_READWRITE(abus_set_r,abus_set_w) +// AM_RANGE(0x00b8, 0x00bb) AM_READWRITE(abus_refresh_r,abus_refresh_w) +// AM_RANGE(0x00c4, 0x00c7) AM_READWRITE(sdram_r,sdram_w) + AM_RANGE(0x00c8, 0x00cb) AM_READ(version_r) // returns 4 for stock Saturn +ADDRESS_MAP_END + +//------------------------------------------------- +// sega_scu_device - constructor +//------------------------------------------------- + +sega_scu_device::sega_scu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SEGA_SCU, tag, owner, clock), + m_scudsp(*this, "scudsp") +{ +} + +void sega_scu_device::static_set_hostcpu(device_t &device, const char *cputag) +{ + sega_scu_device &dev = downcast<sega_scu_device &>(device); + dev.m_hostcpu_tag = cputag; +} + + +//------------------------------------------------- +// add_device_mconfig - device-specific machine +// configuration addiitons +//------------------------------------------------- + +static ADDRESS_MAP_START( scudsp_mem, AS_PROGRAM, 32, sega_scu_device ) + AM_RANGE(0x00, 0xff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( scudsp_data, AS_DATA, 32, sega_scu_device ) + AM_RANGE(0x00, 0xff) AM_RAM +ADDRESS_MAP_END + +READ16_MEMBER(sega_scu_device::scudsp_dma_r) +{ + //address_space &program = m_maincpu->space(AS_PROGRAM); + offs_t addr = offset; + +// printf("%08x\n",addr); + + return m_hostspace->read_word(addr,mem_mask); +} + + +WRITE16_MEMBER(sega_scu_device::scudsp_dma_w) +{ + //address_space &program = m_maincpu->space(AS_PROGRAM); + offs_t addr = offset; + +// printf("%08x %02x\n",addr,data); + + m_hostspace->write_word(addr, data,mem_mask); +} + +MACHINE_CONFIG_MEMBER(sega_scu_device::device_add_mconfig) + MCFG_CPU_ADD("scudsp", SCUDSP, XTAL_57_2727MHz/4) // 14 MHz + MCFG_CPU_PROGRAM_MAP(scudsp_mem) + MCFG_CPU_DATA_MAP(scudsp_data) + MCFG_SCUDSP_OUT_IRQ_CB(DEVWRITELINE(DEVICE_SELF, sega_scu_device, scudsp_end_w)) + MCFG_SCUDSP_IN_DMA_CB(READ16(sega_scu_device, scudsp_dma_r)) + MCFG_SCUDSP_OUT_DMA_CB(WRITE16(sega_scu_device, scudsp_dma_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sega_scu_device::device_start() +{ + save_item(NAME(m_ist)); + save_item(NAME(m_ism)); + save_item(NAME(m_t0c)); + save_item(NAME(m_t1s)); + save_item(NAME(m_t1md)); + + m_hostcpu = machine().device<sh2_device>(m_hostcpu_tag);//machine().device(m_hostcpu_tag); + m_hostspace = &m_hostcpu->space(AS_PROGRAM); + + m_dma_timer[0] = timer_alloc(DMALV0_ID); + m_dma_timer[1] = timer_alloc(DMALV1_ID); + m_dma_timer[2] = timer_alloc(DMALV2_ID); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sega_scu_device::device_reset() +{ + m_ism = 0xbfff; + m_ist = 0; + + for(int i=0;i<3;i++) + { + m_dma[i].start_factor = 7; + m_dma_timer[i]->reset(); + } + + m_status = 0; + m_scudsp->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + +} + + +void sega_scu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + + switch(id) + { + case DMALV0_ID: + case DMALV1_ID: + case DMALV2_ID: + { + const int irqlevel = id == 0 ? 5 : 6; + const int irqvector = 0x4b - id; + const uint16_t irqmask = 1 << (11-id); + + if(!(m_ism & irqmask)) + m_hostcpu->set_input_line_and_vector(irqlevel, HOLD_LINE, irqvector); + else + m_ist |= (irqmask); + + update_dma_status(id,false); + machine().scheduler().synchronize(); // force resync + break; + } + default: + break; + } +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//************************************************************************** +// DMA +//************************************************************************** + +uint32_t sega_scu_device::dma_common_r(uint8_t offset,uint8_t level) +{ + switch(offset) + { + case 0x00/4: // source + return m_dma[level].src; + case 0x04/4: // destination + return m_dma[level].dst; + case 0x08/4: // size + return m_dma[level].size; + case 0x0c/4: + return 0; // DxAD, write only + case 0x10/4: + return 0; // DxEN / DxGO, write only + case 0x14/4: + return 0; // DxMOD / DxRUP / DxWUP / DxFT, write only + } + + // can't happen anyway + return 0; +} + +void sega_scu_device::dma_common_w(uint8_t offset,uint8_t level,uint32_t data) +{ + switch(offset) + { + case 0x00/4: // source + m_dma[level].src = data & 0x07ffffff; + break; + case 0x04/4: // destination + m_dma[level].dst = data & 0x07ffffff; + break; + case 0x08/4: // size, lv0 is bigger than the others + m_dma[level].size = data & ((level == 0) ? 0x000fffff : 0xfff); + break; + case 0x0c/4: // DxAD + m_dma[level].src_add = (data & 0x100) ? 4 : 0; + m_dma[level].dst_add = 1 << (data & 7); + if(m_dma[level].dst_add == 1) { m_dma[level].dst_add = 0; } + break; + case 0x10/4: // DxEN / DxGO + m_dma[level].enable_mask = BIT(data,8); + + // check if DxGO is enabled for start factor = 7 + if(m_dma[level].enable_mask == true && data & 1 && m_dma[level].start_factor == 7) + { + if(m_dma[level].indirect_mode == true) + handle_dma_indirect(level); + else + handle_dma_direct(level); + } + break; + case 0x14/4: // DxMOD / DxRUP / DxWUP / DxFT, write only + m_dma[level].indirect_mode = BIT(data,24); + m_dma[level].rup = BIT(data,16); + m_dma[level].wup = BIT(data,8); + m_dma[level].start_factor = data & 7; + if(m_dma[level].indirect_mode == true) + { + //if(LOG_SCU) logerror("Indirect Mode DMA lv %d set\n",level); + if(m_dma[level].wup == false) + m_dma[level].index = m_dma[level].dst; + } + + break; + } +} + +inline void sega_scu_device::update_dma_status(uint8_t level,bool state) +{ + if(state) + m_status|=(0x10 << 4 * level); + else + m_status&=~(0x10 << 4 * level); +} + +void sega_scu_device::handle_dma_direct(uint8_t level) +{ + uint32_t tmp_src,tmp_dst,total_size; + uint8_t cd_transfer_flag; + + #if 0 + if(m_dma[level].src_add == 0 || (m_dma[level].dst_add != 2 && m_dma[level].dst_add != 4)) + { + if(LOG_SCU) printf("DMA lv %d transfer START\n" + "Start %08x End %08x Size %04x\n",dma_ch,m_scu.src[dma_ch],m_scu.dst[dma_ch],m_scu.size[dma_ch]); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",m_scu.src_add[dma_ch],m_scu.dst_add[dma_ch]); + } + #endif + + // Game Basic, World Cup 98 and Batman Forever trips this, according to the docs the SCU can't transfer from BIOS area (can't communicate from/to that bus) + if((m_dma[level].src & 0x07f00000) == 0) + { + //popmessage("Warning: SCU transfer from BIOS area, contact MAMEdev"); + if(!(m_ism & IRQ_DMAILL)) + m_hostcpu->set_input_line_and_vector(3, HOLD_LINE, 0x4c); + else + m_ist |= (IRQ_DMAILL); + return; + } + + update_dma_status(level,true); + + /* max size */ + if(m_dma[level].size == 0) { m_dma[level].size = (level == 0) ? 0x00100000 : 0x1000; } + + tmp_src = tmp_dst = 0; + + total_size = m_dma[level].size ; + if(m_dma[level].rup == false) tmp_src = m_dma[level].src; + if(m_dma[level].wup == false) tmp_dst = m_dma[level].dst; + + cd_transfer_flag = m_dma[level].src_add == 0 && m_dma[level].src == 0x05818000; + + /* TODO: Many games directly accesses CD-ROM register 0x05818000, it must be a dword access with current implementation otherwise it won't work */ + if(cd_transfer_flag) + { + int i; + if((m_dma[level].dst & 0x07000000) == 0x06000000) + m_dma[level].dst_add = 4; + else + m_dma[level].dst_add <<= 1; + + for (i = 0; i < m_dma[level].size;i+=m_dma[level].dst_add) + { + m_hostspace->write_dword(m_dma[level].dst,m_hostspace->read_dword(m_dma[level].src)); + if(m_dma[level].dst_add == 8) + m_hostspace->write_dword(m_dma[level].dst+4,m_hostspace->read_dword(m_dma[level].src)); + + m_dma[level].src += m_dma[level].src_add; + m_dma[level].dst += m_dma[level].dst_add; + } + } + else + { + int i; + uint8_t src_shift; + + src_shift = ((m_dma[level].src & 2) >> 1) ^ 1; + + for (i = 0; i < m_dma[level].size; i+=2) + { + dma_single_transfer(m_dma[level].src, m_dma[level].dst, &src_shift); + + if(src_shift) + m_dma[level].src+= m_dma[level].src_add ; + + /* if target is Work RAM H, the add value is fixed, behaviour confirmed by Final Romance 2, Virtual Mahjong and Burning Rangers */ + m_dma[level].dst += ((m_dma[level].dst & 0x07000000) == 0x06000000) ? 2 : m_dma[level].dst_add; + } + } + + /* Burning Rangers doesn't agree with this. */ +// m_scu.size[dma_ch] = 0; + if(m_dma[level].rup == false) m_dma[level].src = tmp_src; + if(m_dma[level].wup == false) m_dma[level].dst = tmp_dst; + + // TODO: Timing is a guess. + m_dma_timer[level]->adjust(m_hostcpu->cycles_to_attotime(total_size/4)); +} + +void sega_scu_device::handle_dma_indirect(uint8_t level) +{ + /*Helper to get out of the cycle*/ + uint8_t job_done = 0; + /*temporary storage for the transfer data*/ + uint32_t tmp_src; + uint32_t indirect_src,indirect_dst; + int32_t indirect_size; + uint32_t total_size = 0; + + update_dma_status(level,true); + + m_dma[level].index = m_dma[level].dst; + + do{ + tmp_src = m_dma[level].index; + + indirect_size = m_hostspace->read_dword(m_dma[level].index); + indirect_dst = m_hostspace->read_dword(m_dma[level].index+4); + indirect_src = m_hostspace->read_dword(m_dma[level].index+8); + + /*Indirect Mode end factor*/ + if(indirect_src & 0x80000000) + job_done = 1; + + #if 0 + if(m_dma[level].src_add == 0 || (m_dma[level].dst_add != 2)) + { + if(LOG_SCU) printf("DMA lv %d indirect mode transfer START\n" + "Index %08x Start %08x End %08x Size %04x\n",dma_ch,tmp_src,indirect_src,indirect_dst,indirect_size); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",m_scu.src_add[dma_ch],m_scu.dst_add[dma_ch]); + } + #endif + + indirect_src &=0x07ffffff; + indirect_dst &=0x07ffffff; + indirect_size &= ((level == 0) ? 0xfffff : 0x3ffff); //TODO: Guardian Heroes sets up a 0x23000 transfer for the FMV? + + if(indirect_size == 0) { indirect_size = (level == 0) ? 0x00100000 : 0x2000; } + + { + int i; + uint8_t src_shift; + + src_shift = ((indirect_src & 2) >> 1) ^ 1; + + for (i = 0; i < indirect_size;i+=2) + { + dma_single_transfer(indirect_src,indirect_dst,&src_shift); + + if(src_shift) + indirect_src+=m_dma[level].src_add; + + indirect_dst += ((m_dma[level].dst & 0x07000000) == 0x06000000) ? 2 : m_dma[level].dst_add; + } + } + + /* Guess: Size + data acquire (1 cycle for src/dst/size) */ + total_size += indirect_size + 3*4; + + //if(DRUP(0)) space.write_dword(tmp_src+8,m_scu.src[0]|job_done ? 0x80000000 : 0); + //if(DWUP(0)) space.write_dword(tmp_src+4,m_scu.dst[0]); + + m_dma[level].index = tmp_src+0xc; + + }while(job_done == 0); + + // TODO: Timing is a guess. + m_dma_timer[level]->adjust(m_hostcpu->cycles_to_attotime(total_size/4)); +} + + +inline void sega_scu_device::dma_single_transfer(uint32_t src, uint32_t dst,uint8_t *src_shift) +{ + uint32_t src_data; + + if(src & 1) + { + /* Road Blaster does a work ram h to color ram with offsetted source address, do some data rotation */ + src_data = ((m_hostspace->read_dword(src & 0x07fffffc) & 0x00ffffff)<<8); + src_data |= ((m_hostspace->read_dword((src & 0x07fffffc)+4) & 0xff000000) >> 24); + src_data >>= (*src_shift)*16; + } + else + src_data = m_hostspace->read_dword(src & 0x07fffffc) >> (*src_shift)*16; + + m_hostspace->write_word(dst,src_data); + + *src_shift ^= 1; +} + +inline void sega_scu_device::dma_start_factor_ack(uint8_t event) +{ + int i; + + for(i=0;i<3;i++) + { + if(m_dma[i].enable_mask == true && m_dma[i].start_factor == event) + { + if(m_dma[i].indirect_mode == true) { handle_dma_indirect(i); } + else { handle_dma_direct(i); } + } + } +} + +READ32_MEMBER(sega_scu_device::dma_lv0_r) { return dma_common_r(offset,0); } +WRITE32_MEMBER(sega_scu_device::dma_lv0_w) { dma_common_w(offset,0,data); } +READ32_MEMBER(sega_scu_device::dma_lv1_r) { return dma_common_r(offset,1); } +WRITE32_MEMBER(sega_scu_device::dma_lv1_w) { dma_common_w(offset,1,data); } +READ32_MEMBER(sega_scu_device::dma_lv2_r) { return dma_common_r(offset,2); } +WRITE32_MEMBER(sega_scu_device::dma_lv2_w) { dma_common_w(offset,2,data); } + +READ32_MEMBER(sega_scu_device::dma_status_r) +{ + return m_status; +} + +//************************************************************************** +// Timers +//************************************************************************** + +WRITE32_MEMBER(sega_scu_device::t0_compare_w ) +{ + COMBINE_DATA(&m_t0c); +} + +WRITE32_MEMBER(sega_scu_device::t1_setdata_w ) +{ + COMBINE_DATA(&m_t1s); +} + +/* + ---- ---x ---- ---- T1MD Timer 1 mode (0=each line, 1=only at timer 0 lines) + ---- ---- ---- ---x TENB Timers enable + */ +WRITE16_MEMBER(sega_scu_device::t1_mode_w ) +{ + m_t1md = BIT(data,8); + m_tenb = BIT(data,0); +} + + +void sega_scu_device::check_scanline_timers(int scanline,int y_step) +{ + if(m_tenb == false) + return; + + int timer0_compare = (m_t0c & 0x3ff)*y_step; + + // Timer 0 + if(scanline == timer0_compare) + { + if(!(m_ism & IRQ_TIMER_0)) + { + m_hostcpu->set_input_line_and_vector(0xc, HOLD_LINE, 0x43 ); + dma_start_factor_ack(3); + } + else + m_ist |= (IRQ_TIMER_0); + } + + // Timer 1 + // TODO: should happen after some time when hblank-in is received then counts down t1s + if( + ((m_t1md == false) && ((scanline % y_step) == 0)) || + ((m_t1md == true) && (scanline == timer0_compare)) ) + { + if(!(m_ism & IRQ_TIMER_1)) + { + m_hostcpu->set_input_line_and_vector(0xb, HOLD_LINE, 0x44 ); + dma_start_factor_ack(4); + } + else + m_ist |= (IRQ_TIMER_1); + } + +} + + +//************************************************************************** +// Interrupt +//************************************************************************** + +READ32_MEMBER(sega_scu_device::irq_mask_r) +{ + return m_ism; +} + +READ32_MEMBER(sega_scu_device::irq_status_r) +{ + return m_ist; +} + +WRITE32_MEMBER(sega_scu_device::irq_mask_w) +{ + COMBINE_DATA(&m_ism); + test_pending_irqs(); +} + +WRITE32_MEMBER(sega_scu_device::irq_status_w) +{ + if(mem_mask != 0xffffffff) + logerror("%s IST write %08x with %08x\n",this->tag(),data,mem_mask); + + m_ist &= data; + test_pending_irqs(); +} + +void sega_scu_device::test_pending_irqs() +{ + int i; + const int irq_level[32] = { 0xf, 0xe, 0xd, 0xc, + 0xb, 0xa, 0x9, 0x8, + 0x8, 0x6, 0x6, 0x5, + 0x3, 0x2, -1, -1, + 0x7, 0x7, 0x7, 0x7, + 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1 }; + + for(i=0;i<32;i++) + { + if((!(m_ism & 1 << i)) && (m_ist & 1 << i)) + { + if(irq_level[i] != -1) /* TODO: cheap check for undefined irqs */ + { + m_hostcpu->set_input_line_and_vector(irq_level[i], HOLD_LINE, 0x40 + i); + m_ist &= ~(1 << i); + return; /* avoid spurious irqs, correct? */ + } + } + } +} + +WRITE_LINE_MEMBER(sega_scu_device::vblank_out_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_VBLANK_OUT)) + { + m_hostcpu->set_input_line_and_vector(0xe, HOLD_LINE, 0x41); + dma_start_factor_ack(1); + } + else + m_ist |= (IRQ_VBLANK_OUT); +} + +WRITE_LINE_MEMBER(sega_scu_device::vblank_in_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_VBLANK_IN)) + { + m_hostcpu->set_input_line_and_vector(0xf, HOLD_LINE ,0x40); + dma_start_factor_ack(0); + } + else + m_ist |= (IRQ_VBLANK_IN); +} + +WRITE_LINE_MEMBER(sega_scu_device::hblank_in_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_HBLANK_IN)) + { + m_hostcpu->set_input_line_and_vector(0xd, HOLD_LINE, 0x42); + dma_start_factor_ack(2); + } + else + m_ist |= (IRQ_HBLANK_IN); +} + +WRITE_LINE_MEMBER(sega_scu_device::vdp1_end_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_VDP1_END)) + { + m_hostcpu->set_input_line_and_vector(0x2, HOLD_LINE, 0x4d); + dma_start_factor_ack(6); + } + else + m_ist |= (IRQ_VDP1_END); +} + +WRITE_LINE_MEMBER(sega_scu_device::sound_req_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_SOUND_REQ)) + { + m_hostcpu->set_input_line_and_vector(9, HOLD_LINE, 0x46); + dma_start_factor_ack(5); + } + else + m_ist |= (IRQ_SOUND_REQ); +} + +WRITE_LINE_MEMBER(sega_scu_device::smpc_irq_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_SMPC)) + m_hostcpu->set_input_line_and_vector(8, HOLD_LINE, 0x47); + else + m_ist |= (IRQ_SMPC); +} + +WRITE_LINE_MEMBER(sega_scu_device::scudsp_end_w) +{ + if(!state) + return; + + if(!(m_ism & IRQ_DSP_END)) + m_hostcpu->set_input_line_and_vector(0xa, HOLD_LINE, 0x45); + else + m_ist |= (IRQ_DSP_END); + +} + +//************************************************************************** +// Miscellanea +//************************************************************************** + +READ32_MEMBER(sega_scu_device::version_r) +{ + return 4; // correct for stock Saturn at least +} |