diff --git a/scripts/src/video.lua b/scripts/src/video.lua index 2220e65fff9..95cccd99bfe 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -804,6 +804,18 @@ if (VIDEOS["V9938"]~=null) then } end +-------------------------------------------------- +-- +--@src/devices/video/zeus2.h,VIDEOS["ZEUS2"] = true +-------------------------------------------------- + +if (VIDEOS["ZEUS2"]~=null) then + files { + MAME_DIR .. "src/devices/video/zeus2.cpp", + MAME_DIR .. "src/devices/video/zeus2.h", + } +end + -------------------------------------------------- -- --@src/devices/video/voodoo.h,VIDEOS["VOODOO"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 8496640ed76..d660e649a5c 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -332,6 +332,7 @@ VIDEOS["V9938"] = true --VIDEOS["VIC4567"] = true VIDEOS["VOODOO"] = true VIDEOS["VOODOO_PCI"] = true +VIDEOS["ZEUS2"] = true -------------------------------------------------- -- specify available machine cores diff --git a/src/devices/cpu/adsp2100/2100ops.hxx b/src/devices/cpu/adsp2100/2100ops.hxx index 31cae1ae59b..78987617a77 100644 --- a/src/devices/cpu/adsp2100/2100ops.hxx +++ b/src/devices/cpu/adsp2100/2100ops.hxx @@ -380,7 +380,7 @@ void adsp21xx_device::write_reg1(int regnum, INT32 val) break; case 3: - logerror("ADSP %04x: Writing to an invalid register!\n", m_ppc); + logerror("ADSP %04x: Writing to an invalid register! RGP=01 RegCode=%1X Val=%04X\n", m_ppc, regnum, val); break; } } @@ -505,7 +505,7 @@ INT32 adsp21xx_device::read_reg3(int regnum) case 0x08: if (!m_sport_rx_cb.isnull()) return m_sport_rx_cb(0); else return 0; case 0x0a: if (!m_sport_rx_cb.isnull()) return m_sport_rx_cb(1); else return 0; case 0x0f: return pc_stack_pop_val(); - default: logerror("ADSP %04x: Reading from an invalid register!\n", m_ppc); return 0; + default: logerror("ADSP %04x: Reading from an invalid register! RGP=b11 RegCode=%1X\n", m_ppc, regnum); return 0; } } diff --git a/src/devices/video/zeus2.cpp b/src/devices/video/zeus2.cpp new file mode 100644 index 00000000000..c1e96dadd8c --- /dev/null +++ b/src/devices/video/zeus2.cpp @@ -0,0 +1,1253 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + Midway Zeus2 Video + +**************************************************************************/ +#include "zeus2.h" + +#define LOG_REGS 0 + +/************************************* +* Constructor +*************************************/ +zeus2_renderer::zeus2_renderer(zeus2_device &state) + : poly_manager(state.machine()) + , m_state(state) +{ +} + +const device_type ZEUS2 = &device_creator; + +zeus2_device::zeus2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ZEUS2, "Midway Zeus2", tag, owner, clock, "zeus2", __FILE__), + m_vblank(*this), m_irq(*this) +{ +} + +/************************************* +* Display interrupt generation +*************************************/ + +TIMER_CALLBACK_MEMBER(zeus2_device::display_irq_off) +{ + m_vblank(CLEAR_LINE); + + //attotime vblank_period = m_screen->time_until_pos(m_zeusbase[0x37] & 0xffff); + + ///* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */ + //if (vblank_period == attotime::zero) + // vblank_period = m_screen->frame_period(); + //vblank_timer->adjust(vblank_period); + vblank_timer->adjust(m_screen->time_until_vblank_start()); + //machine().scheduler().timer_set(attotime::from_hz(30000000), timer_expired_delegate(FUNC(zeus2_device::display_irq), this)); +} + +TIMER_CALLBACK_MEMBER(zeus2_device::display_irq) +{ + m_vblank(ASSERT_LINE); + /* set a timer for the next off state */ + //machine().scheduler().timer_set(m_screen->time_until_pos(0), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this), 0, this); + machine().scheduler().timer_set(m_screen->time_until_vblank_end(), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this), 0, this); + //machine().scheduler().timer_set(attotime::from_hz(30000000), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this)); +} + +TIMER_CALLBACK_MEMBER(zeus2_device::int_timer_callback) +{ + //m_maincpu->set_input_line(2, ASSERT_LINE); + m_irq(ASSERT_LINE); +} + +/************************************* + * Video startup + *************************************/ + + +void zeus2_device::device_start() +{ + + /* allocate memory for "wave" RAM */ + waveram[0] = auto_alloc_array(machine(), UINT32, WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8/4); + waveram[1] = auto_alloc_array(machine(), UINT32, WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 12/4); + + /* initialize polygon engine */ + poly = auto_alloc(machine(), zeus2_renderer(*this)); + + //m_screen = machine().first_screen(); + m_screen = downcast(machine().device("screen")); + m_vblank.resolve_safe(); + m_irq.resolve_safe(); + + /* we need to cleanup on exit */ + //machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(zeus2_device::exit_handler2), this)); + + int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(zeus2_device::int_timer_callback), this)); + vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(zeus2_device::display_irq), this)); + + /* save states */ + save_pointer(NAME(waveram[0]), WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8 / sizeof(waveram[0][0])); + save_pointer(NAME(waveram[1]), WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 12 / sizeof(waveram[1][0])); + save_pointer(NAME(m_zeusbase), sizeof(m_zeusbase)); + save_item(NAME(zeus_fifo)); + save_item(NAME(zeus_fifo_words)); + save_item(NAME(zeus_cliprect.min_x)); + save_item(NAME(zeus_cliprect.max_x)); + save_item(NAME(zeus_cliprect.min_y)); + save_item(NAME(zeus_cliprect.max_y)); + save_item(NAME(zeus_matrix)); + save_item(NAME(zeus_point)); + save_item(NAME(zeus_texbase)); +} + +void zeus2_device::device_reset() +{ + memset(m_zeusbase, 0, sizeof(m_zeusbase)); + zbase = 2.0f; + m_yScale = 0; + yoffs = 0; + texel_width = 256; + zeus_renderbase = waveram[1]; + zeus_fifo_words = 0; +} + +void zeus2_device::device_stop() +{ +#if DUMP_WAVE_RAM + FILE *f = fopen("waveram.dmp", "w"); + int i; + + for (i = 0; i < WAVERAM0_WIDTH * WAVERAM0_HEIGHT; i++) + { + if (i % 4 == 0) fprintf(f, "%03X%03X: ", i / WAVERAM0_WIDTH, i % WAVERAM0_WIDTH); + fprintf(f, " %08X %08X ", + WAVERAM_READ32(waveram[0], i*2+0), + WAVERAM_READ32(waveram[0], i*2+1)); + if (i % 4 == 3) fprintf(f, "\n"); + } + fclose(f); +#endif + +#if TRACK_REG_USAGE +{ + reg_info *info; + int regnum; + + for (regnum = 0; regnum < 0x80; regnum++) + { + printf("Register %02X\n", regnum); + if (regread_count[regnum] == 0) + printf("\tNever read\n"); + else + printf("\tRead %d times\n", regread_count[regnum]); + + if (regwrite_count[regnum] == 0) + printf("\tNever written\n"); + else + { + printf("\tWritten %d times\n", regwrite_count[regnum]); + for (info = regdata[regnum]; info != nullptr; info = info->next) + printf("\t%08X\n", info->value); + } + } + + for (regnum = 0; regnum < 0x100; regnum++) + if (subregwrite_count[regnum] != 0) + { + printf("Sub-Register %02X (%d writes)\n", regnum, subregwrite_count[regnum]); + for (info = subregdata[regnum]; info != nullptr; info = info->next) + printf("\t%08X\n", info->value); + } +} +#endif + +} + + + +/************************************* + * + * Video update + * + *************************************/ + +UINT32 zeus2_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x, y; + + poly->wait(); + +if (machine().input().code_pressed(KEYCODE_UP)) { zbase += 1.0f; popmessage("Zbase = %f", (double) zbase); } +if (machine().input().code_pressed(KEYCODE_DOWN)) { zbase -= 1.0f; popmessage("Zbase = %f", (double) zbase); } + + /* normal update case */ + if (!machine().input().code_pressed(KEYCODE_W)) + { + const void *base = waveram1_ptr_from_expanded_addr(m_zeusbase[0x38] >> m_yScale); + int xoffs = screen.visible_area().min_x; + for (y = cliprect.min_y; y <= cliprect.max_y; y++) + { + UINT32 *dest = &bitmap.pix32(y); + UINT32 bufY = y >> m_yScale; + UINT32 bufOffsX = (m_yScale && (y & 1)) ? 0x200 : 0; + for (x = cliprect.min_x; x <= cliprect.max_x; x++) { + UINT32 bufX = x - xoffs + bufOffsX; + dest[x] = WAVERAM_READPIX(base, bufY, bufX); + //dest[x] = WAVERAM_READPIX(base, y, x - xoffs); + } + } + } + + /* waveram drawing case */ + else + { + const UINT64 *base; + + if (machine().input().code_pressed(KEYCODE_DOWN)) yoffs += machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1; + if (machine().input().code_pressed(KEYCODE_UP)) yoffs -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1; + if (machine().input().code_pressed(KEYCODE_LEFT) && texel_width > 4) { texel_width >>= 1; while (machine().input().code_pressed(KEYCODE_LEFT)) ; } + if (machine().input().code_pressed(KEYCODE_RIGHT) && texel_width < 512) { texel_width <<= 1; while (machine().input().code_pressed(KEYCODE_RIGHT)) ; } + + if (yoffs < 0) yoffs = 0; + if (1) + base = (const UINT64 *)waveram0_ptr_from_expanded_addr(yoffs << 16); + else + base = (const UINT64 *)waveram1_ptr_from_expanded_addr(yoffs << 16); + + int xoffs = screen.visible_area().min_x; + for (y = cliprect.min_y; y <= cliprect.max_y; y++) + { + UINT32 *dest = &bitmap.pix32(y); + for (x = cliprect.min_x; x <= cliprect.max_x; x++) + { + if (1) { + UINT8 tex = get_texel_8bit(base, y, x, texel_width); + dest[x] = (tex << 16) | (tex << 8) | tex; + } + else { + dest[x] = WAVERAM_READPIX(base, y, x - xoffs); + } + } + } + popmessage("offs = %06X", yoffs); + } + + return 0; +} + + + +/************************************* + * + * Core read handler + * + *************************************/ + +READ32_MEMBER( zeus2_device::zeus2_r ) +{ + int logit = (offset != 0x00 && offset != 0x01 && + offset != 0x48 && offset != 0x49 && + offset != 0x54 && offset != 0x58 && offset != 0x59 && offset != 0x5a); + logit &= LOG_REGS; + UINT32 result = m_zeusbase[offset]; +#if TRACK_REG_USAGE + regread_count[offset]++; +#endif + + switch (offset) + { + case 0x00: + result = 0x20; + break; + + case 0x01: + /* bit $000C0070 are tested in a loop until 0 */ + /* bits $00080000 is tested in a loop until 0 */ + /* bit $00000004 is tested for toggling; probably VBLANK */ + result = 0x00; + if (m_screen->vblank()) + result |= 0x04; + break; + + case 0x07: + /* this is needed to pass the self-test in thegrid */ + result = 0x10451998; + break; + + case 0x54: + /* both upper 16 bits and lower 16 bits seem to be used as vertical counters */ + result = (m_screen->vpos() << 16) | m_screen->vpos(); + break; + } + + if (logit) + logerror("%08X:zeus2_r(%02X) = %08X\n", machine().device("maincpu")->safe_pc(), offset, result); + + return result; +} + + + +/************************************* + * + * Core write handler + * + *************************************/ + +WRITE32_MEMBER( zeus2_device::zeus2_w ) +{ + int logit = (offset != 0x08 && + (offset != 0x20 || data != 0) && + offset != 0x40 && offset != 0x41 && offset != 0x48 && offset != 0x49 && offset != 0x4e && + offset != 0x50 && offset != 0x51 && offset != 0x57 && offset != 0x58 && offset != 0x59 && offset != 0x5a && offset != 0x5e); + logit &= LOG_REGS; + if (logit) + logerror("%08X:zeus2_w", machine().device("maincpu")->safe_pc()); + zeus2_register32_w(offset, data, logit); +} + + + +/************************************* + * + * Handle register writes + * + *************************************/ + +void zeus2_device::zeus2_register32_w(offs_t offset, UINT32 data, int logit) +{ + UINT32 oldval = m_zeusbase[offset]; + +#if TRACK_REG_USAGE +regwrite_count[offset]++; +if (regdata_count[offset] < 256) +{ + reg_info **tailptr; + + for (tailptr = ®data[offset]; *tailptr != nullptr; tailptr = &(*tailptr)->next) + if ((*tailptr)->value == data) + break; + if (*tailptr == nullptr) + { + *tailptr = alloc_or_die(reg_info); + (*tailptr)->next = nullptr; + (*tailptr)->value = data; + regdata_count[offset]++; + } +} +#endif + + /* writes to register $CC need to force a partial update */ +// if ((offset & ~1) == 0xcc) +// m_screen->update_partial(m_screen->vpos()); + + /* always write to low word? */ + m_zeusbase[offset] = data; + + /* log appropriately */ + if (logit) + logerror("(%02X) = %08X\n", offset, data); + + /* handle the update */ + zeus2_register_update(offset, oldval, logit); +} + + + +/************************************* + * + * Update state after a register write + * + *************************************/ + +void zeus2_device::zeus2_register_update(offs_t offset, UINT32 oldval, int logit) +{ + /* handle the writes; only trigger on low accesses */ + switch (offset) + { + case 0x08: + zeus_fifo[zeus_fifo_words++] = m_zeusbase[0x08]; + if (zeus2_fifo_process(zeus_fifo, zeus_fifo_words)) + zeus_fifo_words = 0; + + /* set the interrupt signal to indicate we can handle more */ + int_timer->adjust(attotime::from_nsec(500)); + break; + + case 0x20: + /* toggles between two values based on the page: + + Page # m_zeusbase[0x20] m_zeusbase[0x38] + ------ -------------- -------------- + 0 $04000190 $00000000 + 1 $04000000 $01900000 + */ + zeus2_pointer_write(m_zeusbase[0x20] >> 24, m_zeusbase[0x20]); + break; + + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + m_screen->update_partial(m_screen->vpos()); + { + // Just a guess. Atlantis startup has two scanlines per physical ram row + if ((m_zeusbase[0x30] & 0xfff) <= 0x100) + m_yScale = 1; + else + m_yScale = 0; + int vtotal = (m_zeusbase[0x37] & 0xffff) << m_yScale; + int htotal = (m_zeusbase[0x34] >> 16); + + rectangle visarea((m_zeusbase[0x33] >> 16), htotal - 1, 0, (m_zeusbase[0x35] & 0xffff)<< m_yScale); + if (htotal > 0 && vtotal > 0 && visarea.min_x < visarea.max_x && visarea.max_y < vtotal) + { + m_screen->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS((double)MIDZEUS_VIDEO_CLOCK / 4.0 / (htotal * vtotal))); + zeus_cliprect = visarea; + zeus_cliprect.max_x -= zeus_cliprect.min_x; + zeus_cliprect.min_x = 0; + // Startup vblank timer + vblank_timer->adjust(attotime::from_hz(30000000)); + } + } + break; + + case 0x38: + { + UINT32 temp = m_zeusbase[0x38]; + m_zeusbase[0x38] = oldval; + m_screen->update_partial(m_screen->vpos()); + log_fifo = machine().input().code_pressed(KEYCODE_L); + log_fifo = 1; + m_zeusbase[0x38] = temp; + } + break; + + case 0x40: + /* in direct mode it latches values */ + if ((m_zeusbase[0x4e] & 0x20) && m_zeusbase[0x40] == 0x00820000) + { + const void *src = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]); + m_zeusbase[0x48] = WAVERAM_READ32(src, 0); + m_zeusbase[0x49] = WAVERAM_READ32(src, 1); + + if (m_zeusbase[0x4e] & 0x40) + { + m_zeusbase[0x41]++; + m_zeusbase[0x41] += (m_zeusbase[0x41] & 0x400) << 6; + m_zeusbase[0x41] &= ~0xfc00; + } + } + break; + case 0x41: + /* this is the address, except in read mode, where it latches values */ + if (m_zeusbase[0x4e] & 0x10) + { + const void *src = waveram0_ptr_from_expanded_addr(oldval); + m_zeusbase[0x41] = oldval; + m_zeusbase[0x48] = WAVERAM_READ32(src, 0); + m_zeusbase[0x49] = WAVERAM_READ32(src, 1); + + if (m_zeusbase[0x4e] & 0x40) + { + m_zeusbase[0x41]++; + m_zeusbase[0x41] += (m_zeusbase[0x41] & 0x400) << 6; + m_zeusbase[0x41] &= ~0xfc00; + } + } else { + // mwskinsa (atlantis) writes 0xffffffff and expects 0x1fff03ff to be read back + m_zeusbase[0x41] &= 0x1fff03ff; + } + break; + + case 0x48: + case 0x49: + /* if we're in write mode, process it */ + if (m_zeusbase[0x40] == 0x00890000) + { + /* + m_zeusbase[0x4e]: + bit 0-1: which register triggers write through + bit 3: enable write through via these registers + bit 4: seems to be set during reads, when 0x41 is used for latching + bit 6: enable autoincrement on write through + */ + if ((m_zeusbase[0x4e] & 0x08) && (offset & 3) == (m_zeusbase[0x4e] & 3)) + { + void *dest = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]); + WAVERAM_WRITE32(dest, 0, m_zeusbase[0x48]); + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x49]); + + if (m_zeusbase[0x4e] & 0x40) + { + m_zeusbase[0x41]++; + m_zeusbase[0x41] += (m_zeusbase[0x41] & 0x400) << 6; + m_zeusbase[0x41] &= ~0xfc00; + } + } + } + + /* make sure we log anything else */ + else if (logit) + logerror("\t[40]=%08X [4E]=%08X\n", m_zeusbase[0x40], m_zeusbase[0x4e]); + break; + + case 0x50: + if ((m_zeusbase[0x50] & 0xffff0000) == 0x00980000) { + // Fast fill? + // Unknow what the exact bit fields are, this is a just a guess + UINT32 lastRow = (((m_zeusbase[0x50] >> 8) & 0xff) << 3) | 0x7; + UINT32 lastCol = (((m_zeusbase[0x50] >> 0) & 0xff) << 2) | 0x3; + UINT32 fillColor = 0x004a4a4a; + void *base = waveram1_ptr_from_expanded_addr(m_zeusbase[0x51]); + for (int y = 0; y <= lastRow; y++) + for (int x = 0; x <= lastCol; x++) + WAVERAM_WRITEPIX(base, y, x, fillColor); + } + else if ((m_zeusbase[0x5e] >> 16) != 0xF208) { + /* If 0x5e==0xf20a0000 (atlantis) or 0xf20d0000 (the grid) then process the read/write now */ + /* + m_zeusbase[0x5e]: + bit 0-1: which register triggers write through + bit 3: enable write through via these registers + bit 4: seems to be set during reads, when 0x51 is used for latching + bit 5: unknown, currently used to specify ordering, but this is suspect + bit 6: enable autoincrement on write through + */ + if (m_zeusbase[0x50] == 0x00890000) + { + void *dest = waveram1_ptr_from_expanded_addr(m_zeusbase[0x51]); + WAVERAM_WRITE32(dest, 0, m_zeusbase[0x58]); + if (m_zeusbase[0x5e] & 0x20) + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x5a]); + else + { + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x59]); + WAVERAM_WRITE32(dest, 2, m_zeusbase[0x5a]); + } + + if (m_zeusbase[0x5e] & 0x40) + { + m_zeusbase[0x51]++; + m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7; + m_zeusbase[0x51] &= ~0xfe00; + } + } + else if (m_zeusbase[0x50] == 0x00720000) { + /* Do the read */ + const void *src = waveram1_ptr_from_expanded_addr(m_zeusbase[0x51]); + m_zeusbase[0x58] = WAVERAM_READ32(src, 0); + m_zeusbase[0x59] = WAVERAM_READ32(src, 1); + m_zeusbase[0x5a] = WAVERAM_READ32(src, 2); + + if (m_zeusbase[0x5e] & 0x40) + { + m_zeusbase[0x51]++; + m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7; + m_zeusbase[0x51] &= ~0xfe00; + } + } + } + break; + case 0x51: + + /* in this mode, crusnexo expects the reads to immediately latch */ + //if ((m_zeusbase[0x50] == 0x00a20000) || (m_zeusbase[0x50] == 0x00720000)) + if ((m_zeusbase[0x50] == 0x00a20000)) + oldval = m_zeusbase[0x51]; + + /* this is the address, except in read mode, where it latches values */ + if ((m_zeusbase[0x5e] & 0x10) || (m_zeusbase[0x50] == 0x00a20000)) + { + const void *src = waveram1_ptr_from_expanded_addr(oldval); + m_zeusbase[0x51] = oldval; + m_zeusbase[0x58] = WAVERAM_READ32(src, 0); + m_zeusbase[0x59] = WAVERAM_READ32(src, 1); + m_zeusbase[0x5a] = WAVERAM_READ32(src, 2); + + if (m_zeusbase[0x5e] & 0x40) + { + m_zeusbase[0x51]++; + m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7; + m_zeusbase[0x51] &= ~0xfe00; + } + } + break; + + case 0x57: + /* thegrid uses this to write either left or right halves of pixels */ + if (m_zeusbase[0x50] == 0x00e90000) + { + void *dest = waveram1_ptr_from_expanded_addr(m_zeusbase[0x51]); + if (m_zeusbase[0x57] & 1) + WAVERAM_WRITE32(dest, 0, m_zeusbase[0x58]); + if (m_zeusbase[0x57] & 4) + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x59]); + } + + /* make sure we log anything else */ + else if (logit) + logerror("\t[50]=%08X [5E]=%08X\n", m_zeusbase[0x50], m_zeusbase[0x5e]); + break; + + case 0x58: + case 0x59: + case 0x5a: + /* if we're in write mode, process it */ + if (m_zeusbase[0x50] == 0x00890000) + { + /* + m_zeusbase[0x5e]: + bit 0-1: which register triggers write through + bit 3: enable write through via these registers + bit 4: seems to be set during reads, when 0x51 is used for latching + bit 5: unknown, currently used to specify ordering, but this is suspect + bit 6: enable autoincrement on write through + */ + if ((m_zeusbase[0x5e] & 0x08) && (offset & 3) == (m_zeusbase[0x5e] & 3)) + { + void *dest = waveram1_ptr_from_expanded_addr(m_zeusbase[0x51]); + WAVERAM_WRITE32(dest, 0, m_zeusbase[0x58]); + if (m_zeusbase[0x5e] & 0x20) + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x5a]); + else + { + WAVERAM_WRITE32(dest, 1, m_zeusbase[0x59]); + WAVERAM_WRITE32(dest, 2, m_zeusbase[0x5a]); + } + + if (m_zeusbase[0x5e] & 0x40) + { + m_zeusbase[0x51]++; + m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7; + m_zeusbase[0x51] &= ~0xfe00; + } + } + } + + /* make sure we log anything else */ + else if (logit) + logerror("\t[50]=%08X [5E]=%08X\n", m_zeusbase[0x50], m_zeusbase[0x5e]); + break; + } +} + + + +/************************************* + * + * Process the FIFO + * + *************************************/ + +void zeus2_device::zeus2_pointer_write(UINT8 which, UINT32 value) +{ +#if TRACK_REG_USAGE +subregwrite_count[which]++; +if (subregdata_count[which] < 256) +{ + reg_info **tailptr; + + for (tailptr = &subregdata[which]; *tailptr != nullptr; tailptr = &(*tailptr)->next) + if ((*tailptr)->value == value) + break; + if (*tailptr == nullptr) + { + *tailptr = alloc_or_die(reg_info); + (*tailptr)->next = nullptr; + (*tailptr)->value = value; + subregdata_count[which]++; + } +} +#endif + + switch (which) + { + case 0x04: + zeus_renderbase = waveram1_ptr_from_expanded_addr(value << 16); + break; + + case 0x05: + zeus_texbase = value % (WAVERAM0_HEIGHT * WAVERAM0_WIDTH); + break; + + case 0x40: + zeus_unknown_40 = value & 0xffffff; + zeus_quad_size = (zeus_unknown_40 == 0) ? 10 : 14; + break; + +#if 0 + case 0x0c: + case 0x0d: + // These seem to have something to do with blending. + // There are fairly unique 0x0C,0x0D pairs for various things: + // Car reflection on initial screen: 0x40, 0x00 + // Additively-blended "flares": 0xFA, 0xFF + // Car windshields (and drivers, apparently): 0x82, 0x7D + // Other minor things: 0xA4, 0x100 + break; +#endif + } +} + +/************************************* + * Process the FIFO + *************************************/ + +int zeus2_device::zeus2_fifo_process(const UINT32 *data, int numwords) +{ + int dataoffs = 0; + + /* handle logging */ + switch (data[0] >> 24) + { + /* 0x05: write 32-bit value to low registers */ + case 0x05: + if (numwords < 2) + return FALSE; + if (log_fifo) + log_fifo_command(data, numwords, " -- reg32"); + if (((data[0] >> 16) & 0x7f) != 0x08) + zeus2_register32_w((data[0] >> 16) & 0x7f, data[1], log_fifo); + break; + + /* 0x08: set matrix and point (thegrid) */ + case 0x08: + if (numwords < 14) + return FALSE; + dataoffs = 1; + + /* 0x07: set matrix and point (crusnexo) */ + case 0x07: + if (numwords < 13) + return FALSE; + + /* extract the matrix from the raw data */ + zeus_matrix[0][0] = tms3203x_device::fp_to_float(data[dataoffs + 1]); + zeus_matrix[0][1] = tms3203x_device::fp_to_float(data[dataoffs + 2]); + zeus_matrix[0][2] = tms3203x_device::fp_to_float(data[dataoffs + 3]); + zeus_matrix[1][0] = tms3203x_device::fp_to_float(data[dataoffs + 4]); + zeus_matrix[1][1] = tms3203x_device::fp_to_float(data[dataoffs + 5]); + zeus_matrix[1][2] = tms3203x_device::fp_to_float(data[dataoffs + 6]); + zeus_matrix[2][0] = tms3203x_device::fp_to_float(data[dataoffs + 7]); + zeus_matrix[2][1] = tms3203x_device::fp_to_float(data[dataoffs + 8]); + zeus_matrix[2][2] = tms3203x_device::fp_to_float(data[dataoffs + 9]); + + /* extract the translation point from the raw data */ + zeus_point[0] = tms3203x_device::fp_to_float(data[dataoffs + 10]); + zeus_point[1] = tms3203x_device::fp_to_float(data[dataoffs + 11]); + zeus_point[2] = tms3203x_device::fp_to_float(data[dataoffs + 12]); + + if (log_fifo) + { + log_fifo_command(data, numwords, ""); + logerror("\n\t\tmatrix ( %8.2f %8.2f %8.2f ) ( %8.2f %8.2f %8.2f ) ( %8.2f %8.2f %8.2f )\n\t\tvector %8.2f %8.2f %8.5f\n", + (double) zeus_matrix[0][0], (double) zeus_matrix[0][1], (double) zeus_matrix[0][2], + (double) zeus_matrix[1][0], (double) zeus_matrix[1][1], (double) zeus_matrix[1][2], + (double) zeus_matrix[2][0], (double) zeus_matrix[2][1], (double) zeus_matrix[2][2], + (double) zeus_point[0], + (double) zeus_point[1], + (double) zeus_point[2]); + } + break; + + /* 0x15: set point only (thegrid) */ + /* 0x16: set point only (crusnexo) */ + case 0x15: + case 0x16: + if (numwords < 4) + return FALSE; + + /* extract the translation point from the raw data */ + zeus_point[0] = tms3203x_device::fp_to_float(data[1]); + zeus_point[1] = tms3203x_device::fp_to_float(data[2]); + zeus_point[2] = tms3203x_device::fp_to_float(data[3]); + + if (log_fifo) + { + log_fifo_command(data, numwords, ""); + logerror("\n\t\tvector %8.2f %8.2f %8.5f\n", + (double) zeus_point[0], + (double) zeus_point[1], + (double) zeus_point[2]); + } + break; + + /* 0x1c: */ + case 0x1c: + if (numwords < 4) + return FALSE; + if (log_fifo) + { + log_fifo_command(data, numwords, " -- unknown control + hack clear screen\n"); + logerror("\t\tvector %8.2f %8.2f %8.5f\n", + (double) tms3203x_device::fp_to_float(data[1]), + (double) tms3203x_device::fp_to_float(data[2]), + (double) tms3203x_device::fp_to_float(data[3])); + + /* extract the translation point from the raw data */ + zeus_point2[0] = tms3203x_device::fp_to_float(data[1]); + zeus_point2[1] = tms3203x_device::fp_to_float(data[2]); + zeus_point2[2] = tms3203x_device::fp_to_float(data[3]); + } + { + /* not right -- just a hack */ + int x, y; + for (y = zeus_cliprect.min_y; y <= zeus_cliprect.max_y; y++) + for (x = zeus_cliprect.min_x; x <= zeus_cliprect.max_x; x++) + waveram_plot_depth(y, x, 0, 0x7fff); + } + break; + + /* 0x23: render model in waveram (thegrid) */ + /* 0x24: render model in waveram (crusnexo) */ + case 0x23: + case 0x24: + if (numwords < 2) + return FALSE; + if (log_fifo) + log_fifo_command(data, numwords, ""); + zeus2_draw_model(data[1], data[0] & 0xffff, log_fifo); + break; + + /* 0x31: sync pipeline? (thegrid) */ + /* 0x32: sync pipeline? (crusnexo) */ + case 0x31: + case 0x32: + if (log_fifo) + log_fifo_command(data, numwords, "\n"); + zeus_quad_size = 10; + break; + + /* 0x38: direct render quad (crusnexo) */ + case 0x38: + if (numwords < 12) + return FALSE; + if (log_fifo) + log_fifo_command(data, numwords, ""); + break; + + /* 0x40: ???? */ + case 0x40: + if (log_fifo) + log_fifo_command(data, numwords, "\n"); + break; + + default: + if (data[0] != 0x2c0) + { + printf("Unknown command %08X\n", data[0]); + if (log_fifo) + log_fifo_command(data, numwords, "\n"); + } + break; + } + return TRUE; +} + +/************************************* + * Draw a model in waveram + *************************************/ + +void zeus2_device::zeus2_draw_model(UINT32 baseaddr, UINT16 count, int logit) +{ + UINT32 databuffer[32]; + int databufcount = 0; + int model_done = FALSE; + UINT32 texoffs = 0; + int quadsize = zeus_quad_size; + + if (logit) + logerror(" -- model @ %08X, len %04X\n", baseaddr, count); + + if (count > 0x1000) + fatalerror("Extreme count\n"); + + while (baseaddr != 0 && !model_done) + { + const void *base = waveram0_ptr_from_expanded_addr(baseaddr); + int curoffs; + + /* reset the objdata address */ + baseaddr = 0; + + /* loop until we run out of data */ + for (curoffs = 0; curoffs <= count; curoffs++) + { + int countneeded = 2; + UINT8 cmd; + + /* accumulate 2 words of data */ + databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 0); + databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 1); + + /* if this is enough, process the command */ + cmd = databuffer[0] >> 24; + if (cmd == 0x38) + countneeded = quadsize; + if (databufcount == countneeded) + { + /* handle logging of the command */ + if (logit) + { + int offs; + logerror("\t"); + for (offs = 0; offs < databufcount; offs++) + logerror("%08X ", databuffer[offs]); + logerror("-- "); + } + + /* handle the command */ + switch (cmd) + { + case 0x21: /* thegrid */ + case 0x22: /* crusnexo */ + if (((databuffer[0] >> 16) & 0xff) == 0x9b) + { + texoffs = databuffer[1]; + if (logit) + logerror("texture offset\n"); + } + else if (logit) + logerror("unknown offset\n"); + break; + + case 0x31: /* thegrid */ + if (logit) + logerror("sync?\n"); + break; + + case 0x35: /* thegrid */ + case 0x36: /* crusnexo */ + if (logit) + logerror("reg32"); + zeus2_register32_w((databuffer[0] >> 16) & 0x7f, databuffer[1], logit); + break; + + case 0x38: /* crusnexo/thegrid */ + poly->zeus2_draw_quad(databuffer, texoffs, logit); + break; + + default: + if (quadsize == 10) + { + logerror("Correcting quad size\n"); + quadsize = 14; + } + if (logit) + logerror("unknown model data\n"); + break; + } + + /* reset the count */ + databufcount = 0; + } + } + } +} + +/************************************* + * Draw a quad + *************************************/ +void zeus2_renderer::zeus2_draw_quad(const UINT32 *databuffer, UINT32 texoffs, int logit) +{ + poly_vertex clipvert[8]; + poly_vertex vert[4]; + // float uscale, vscale; + float maxy, maxx; + // int val1, val2, texwshift; + int numverts; + int i; + // INT16 normal[3]; + // INT32 rotnormal[3]; + int texmode = texoffs & 0xffff; + + if (logit) + m_state.logerror("quad\n"); + + if (machine().input().code_pressed(KEYCODE_Q) && (texoffs & 0xffff) == 0x119) return; + if (machine().input().code_pressed(KEYCODE_E) && (texoffs & 0xffff) == 0x01d) return; + if (machine().input().code_pressed(KEYCODE_R) && (texoffs & 0xffff) == 0x11d) return; + if (machine().input().code_pressed(KEYCODE_T) && (texoffs & 0xffff) == 0x05d) return; + if (machine().input().code_pressed(KEYCODE_Y) && (texoffs & 0xffff) == 0x0dd) return; + //if (machine().input().code_pressed(KEYCODE_U) && (texoffs & 0xffff) == 0x119) return; + //if (machine().input().code_pressed(KEYCODE_I) && (texoffs & 0xffff) == 0x119) return; + //if (machine().input().code_pressed(KEYCODE_O) && (texoffs & 0xffff) == 0x119) return; + //if (machine().input().code_pressed(KEYCODE_L) && (texoffs & 0x100)) return; + + /* + 0 38800000 + 1 x2 | x1 + 2 v1 | u1 + 3 y2 | y1 + 4 v2 | u2 + 5 z2 | z1 + 6 v3 | u3 + 7 v4 | u4 + 8 ??? + 9 x4 | x3 + 10 y4 | y3 + 11 z4 | z3 + + In memory: + +0 = ??? + +1 = set via $05410000/value + +2 = x1 + +3 = y1 + +4 = z1 + +5 = x2 + +6 = y2 + +7 = z2 + +8 = x3 + +9 = y3 + +10= z3 + +11= x4 + +12= y4 + +13= z4 + +14= uv1 + +15= uv2 + +16= uv3 + +17= uv4 + +18= set via $05200000/$05000000 | (value << 10) (uvoffset?) + +19= ??? + + + 38810000 00000000 00C7|FF38 FF5E|FF5E 15400154 11400114 00000000 00000000 FF38|00C7 00A3|00A3 -- quad + xxxx|xxxx yyyy|yyyy xxxx|xxxx yyyy|yyyy + */ + + /* extract raw x,y,z */ + vert[0].x = (INT16)databuffer[2]; + vert[0].y = (INT16)databuffer[3]; + vert[0].p[0] = (INT16)databuffer[6]; + vert[0].p[1] = (databuffer[1] >> 2) & 0xff; + vert[0].p[2] = (databuffer[1] >> 18) & 0xff; + + vert[1].x = (INT16)(databuffer[2] >> 16); + vert[1].y = (INT16)(databuffer[3] >> 16); + vert[1].p[0] = (INT16)(databuffer[6] >> 16); + vert[1].p[1] = (databuffer[4] >> 2) & 0xff; + vert[1].p[2] = (databuffer[4] >> 12) & 0xff; + + vert[2].x = (INT16)databuffer[8]; + vert[2].y = (INT16)databuffer[9]; + vert[2].p[0] = (INT16)databuffer[7]; + vert[2].p[1] = (databuffer[4] >> 22) & 0xff; + vert[2].p[2] = (databuffer[5] >> 2) & 0xff; + + vert[3].x = (INT16)(databuffer[8] >> 16); + vert[3].y = (INT16)(databuffer[9] >> 16); + vert[3].p[0] = (INT16)(databuffer[7] >> 16); + vert[3].p[1] = (databuffer[5] >> 12) & 0xff; + vert[3].p[2] = (databuffer[5] >> 22) & 0xff; + + /* + vert[0].x = (INT16)databuffer[1]; + vert[0].y = (INT16)databuffer[3]; + vert[0].p[0] = (INT16)databuffer[5]; + vert[0].p[1] = (UINT16)databuffer[2]; + vert[0].p[2] = (UINT16)(databuffer[2] >> 16); + + vert[1].x = (INT16)(databuffer[1] >> 16); + vert[1].y = (INT16)(databuffer[3] >> 16); + vert[1].p[0] = (INT16)(databuffer[5] >> 16); + vert[1].p[1] = (UINT16)databuffer[4]; + vert[1].p[2] = (UINT16)(databuffer[4] >> 16); + + vert[2].x = (INT16)databuffer[9]; + vert[2].y = (INT16)databuffer[10]; + vert[2].p[0] = (INT16)databuffer[11]; + vert[2].p[1] = (UINT16)databuffer[6]; + vert[2].p[2] = (UINT16)(databuffer[6] >> 16); + + vert[3].x = (INT16)(databuffer[9] >> 16); + vert[3].y = (INT16)(databuffer[10] >> 16); + vert[3].p[0] = (INT16)(databuffer[11] >> 16); + vert[3].p[1] = (UINT16)databuffer[7]; + vert[3].p[2] = (UINT16)(databuffer[7] >> 16); + */ + for (i = 0; i < 4; i++) + { + float x = vert[i].x; + float y = vert[i].y; + float z = vert[i].p[0]; + + vert[i].x = x * m_state.zeus_matrix[0][0] + y * m_state.zeus_matrix[0][1] + z * m_state.zeus_matrix[0][2] + m_state.zeus_point[0]; + vert[i].y = x * m_state.zeus_matrix[1][0] + y * m_state.zeus_matrix[1][1] + z * m_state.zeus_matrix[1][2] + m_state.zeus_point[1]; + vert[i].p[0] = x * m_state.zeus_matrix[2][0] + y * m_state.zeus_matrix[2][1] + z * m_state.zeus_matrix[2][2] + m_state.zeus_point[2]; + vert[i].p[0] += m_state.zbase; + vert[i].p[2] += texoffs >> 16; + vert[i].p[1] *= 256.0f; + vert[i].p[2] *= 256.0f; + + if (logit) + { + m_state.logerror("\t\t(%f,%f,%f) (%02X,%02X)\n", + (double)vert[i].x, (double)vert[i].y, (double)vert[i].p[0], + (int)(vert[i].p[1] / 256.0f), (int)(vert[i].p[2] / 256.0f)); + } + } + + numverts = this->zclip_if_less(4, &vert[0], &clipvert[0], 4, 1.0f / 512.0f / 4.0f); + if (numverts < 3) + return; + + maxx = maxy = -1000.0f; + for (i = 0; i < numverts; i++) + { + // 412.0f here works for crusnexo + float ooz = 512.0f / clipvert[i].p[0]; + + // ooz *= 1.0f / (512.0f * 512.0f); + + clipvert[i].x *= ooz; + clipvert[i].y *= ooz; + clipvert[i].x += 256.5f; + clipvert[i].y += 200.5f; + clipvert[i].p[0] *= 65536.0f * 16.0f; + + maxx = MAX(maxx, clipvert[i].x); + maxy = MAX(maxy, clipvert[i].y); + if (logit) + m_state.logerror("\t\t\tTranslated=(%f,%f)\n", (double)clipvert[i].x, (double)clipvert[i].y); + } + for (i = 0; i < numverts; i++) + { + if (clipvert[i].x == maxx) + clipvert[i].x += 0.0005f; + if (clipvert[i].y == maxy) + clipvert[i].y += 0.0005f; + } + + zeus2_poly_extra_data& extra = this->object_data_alloc(); + switch (texmode) + { + case 0x01d: /* crusnexo: RHS of score bar */ + case 0x05d: /* crusnexo: background, road */ + case 0x0dd: /* crusnexo: license plate letters */ + case 0x11d: /* crusnexo: LHS of score bar */ + case 0x15d: /* crusnexo */ + case 0x85d: /* crusnexo */ + case 0x95d: /* crusnexo */ + case 0xc1d: /* crusnexo */ + case 0xc5d: /* crusnexo */ + extra.texwidth = 256; + break; + + case 0x059: /* crusnexo */ + case 0x0d9: /* crusnexo */ + case 0x119: /* crusnexo: license plates */ + case 0x159: /* crusnexo */ + extra.texwidth = 128; + break; + + case 0x055: /* crusnexo */ + case 0x155: /* crusnexo */ + extra.texwidth = 64; + break; + + default: + { + static UINT8 hits[0x10000]; + if (!hits[(texoffs & 0xffff)]) + { + hits[(texoffs & 0xffff)] = 1; + printf("format = %04X\n", (texoffs & 0xffff)); + } + break; + } + } + + extra.solidcolor = 0;//m_zeusbase[0x00] & 0x7fff; + extra.zoffset = 0;//m_zeusbase[0x7e] >> 16; + extra.alpha = 0;//m_zeusbase[0x4e]; + extra.transcolor = 0x100;//((databuffer[1] >> 16) & 1) ? 0 : 0x100; + extra.texbase = WAVERAM_BLOCK0_EXT(m_state.zeus_texbase); + extra.palbase = m_state.waveram0_ptr_from_expanded_addr(m_state.m_zeusbase[0x41]); + + // Note: Before being converted to the "poly.h" interface, this used to call the polylgcy function + // poly_render_quad_fan. The behavior seems to be the same as it once was after a few short + // tests, but the (numverts == 5) statement below may actually be a quad fan instead of a 5-sided + // polygon. + if (numverts == 3) + render_triangle(m_state.zeus_cliprect, render_delegate(FUNC(zeus2_renderer::render_poly_8bit), this), 4, clipvert[0], clipvert[1], clipvert[2]); + else if (numverts == 4) + render_polygon<4>(m_state.zeus_cliprect, render_delegate(FUNC(zeus2_renderer::render_poly_8bit), this), 4, clipvert); + else if (numverts == 5) + render_polygon<5>(m_state.zeus_cliprect, render_delegate(FUNC(zeus2_renderer::render_poly_8bit), this), 4, clipvert); +} + + + +/************************************* +* Rasterizers +*************************************/ + +void zeus2_renderer::render_poly_8bit(INT32 scanline, const extent_t& extent, const zeus2_poly_extra_data& object, int threadid) +{ + INT32 curz = extent.param[0].start; + INT32 curu = extent.param[1].start; + INT32 curv = extent.param[2].start; + // INT32 curi = extent.param[3].start; + INT32 dzdx = extent.param[0].dpdx; + INT32 dudx = extent.param[1].dpdx; + INT32 dvdx = extent.param[2].dpdx; + // INT32 didx = extent.param[3].dpdx; + const void *texbase = object.texbase; + const void *palbase = object.palbase; + UINT16 transcolor = object.transcolor; + int texwidth = object.texwidth; + int x; + + for (x = extent.startx; x < extent.stopx; x++) + { + UINT16 *depthptr = WAVERAM_PTRDEPTH(m_state.zeus_renderbase, scanline, x); + INT32 depth = (curz >> 16) + object.zoffset; + if (depth > 0x7fff) depth = 0x7fff; + if (depth >= 0 && depth <= *depthptr) + { + int u0 = (curu >> 8);// & (texwidth - 1); + int v0 = (curv >> 8);// & 255; + int u1 = (u0 + 1); + int v1 = (v0 + 1); + UINT8 texel0 = m_state.get_texel_8bit(texbase, v0, u0, texwidth); + UINT8 texel1 = m_state.get_texel_8bit(texbase, v0, u1, texwidth); + UINT8 texel2 = m_state.get_texel_8bit(texbase, v1, u0, texwidth); + UINT8 texel3 = m_state.get_texel_8bit(texbase, v1, u1, texwidth); + if (texel0 != transcolor) + { + UINT32 color0 = WAVERAM_READ16(palbase, texel0); + UINT32 color1 = WAVERAM_READ16(palbase, texel1); + UINT32 color2 = WAVERAM_READ16(palbase, texel2); + UINT32 color3 = WAVERAM_READ16(palbase, texel3); + color0 = ((color0 & 0x7c00) << 9) | ((color0 & 0x3e0) << 6) | ((color0 & 0x1f) << 3); + color1 = ((color1 & 0x7c00) << 9) | ((color1 & 0x3e0) << 6) | ((color1 & 0x1f) << 3); + color2 = ((color2 & 0x7c00) << 9) | ((color2 & 0x3e0) << 6) | ((color2 & 0x1f) << 3); + color3 = ((color3 & 0x7c00) << 9) | ((color3 & 0x3e0) << 6) | ((color3 & 0x1f) << 3); + rgb_t filtered = rgbaint_t::bilinear_filter(color0, color1, color2, color3, curu, curv); + WAVERAM_WRITEPIX(m_state.zeus_renderbase, scanline, x, filtered); + *depthptr = depth; + } + } + + curz += dzdx; + curu += dudx; + curv += dvdx; + // curi += didx; + } +} + +/************************************* + * Debugging tools + *************************************/ + +void zeus2_device::log_fifo_command(const UINT32 *data, int numwords, const char *suffix) +{ + int wordnum; + + logerror("Zeus cmd %02X :", data[0] >> 24); + for (wordnum = 0; wordnum < numwords; wordnum++) + logerror(" %08X", data[wordnum]); + logerror("%s", suffix); +} diff --git a/src/devices/video/zeus2.h b/src/devices/video/zeus2.h new file mode 100644 index 00000000000..a466846d2e0 --- /dev/null +++ b/src/devices/video/zeus2.h @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + Midway Zeus2 Video + +**************************************************************************/ +#ifndef __ZEUS2_H__ +#define __ZEUS2_H__ + +#include "emu.h" +#include "video/poly.h" +#include "video/rgbutil.h" +#include "cpu/tms32031/tms32031.h" + +#pragma once + +/************************************* +* Constants +*************************************/ +#define MIDZEUS_VIDEO_CLOCK XTAL_66_6667MHz + +#define DUMP_WAVE_RAM 0 +#define TRACK_REG_USAGE 0 + +#define WAVERAM0_WIDTH 1024 +#define WAVERAM0_HEIGHT 2048 + +//#define WAVERAM1_WIDTH 512 +#define WAVERAM1_WIDTH 512 +#define WAVERAM1_HEIGHT 1024 +//#define WAVERAM1_HEIGHT 1024 + +/************************************* +* Type definitions +*************************************/ + +struct zeus2_poly_extra_data +{ + const void * palbase; + const void * texbase; + UINT16 solidcolor; + INT16 zoffset; + UINT16 transcolor; + UINT16 texwidth; + UINT16 color; + UINT32 alpha; +}; + +/************************************* +* Macros +*************************************/ + +#define WAVERAM_BLOCK0(blocknum) ((void *)((UINT8 *)waveram[0] + 8 * (blocknum))) +#define WAVERAM_BLOCK1(blocknum) ((void *)((UINT8 *)waveram[1] + 12 * (blocknum))) +#define WAVERAM_BLOCK0_EXT(blocknum) ((void *)((UINT8 *)m_state.waveram[0] + 8 * (blocknum))) +#define WAVERAM_BLOCK1_EXT(blocknum) ((void *)((UINT8 *)m_state.waveram[1] + 12 * (blocknum))) + +#define WAVERAM_PTR8(base, bytenum) ((UINT8 *)(base) + BYTE4_XOR_LE(bytenum)) +#define WAVERAM_READ8(base, bytenum) (*WAVERAM_PTR8(base, bytenum)) +#define WAVERAM_WRITE8(base, bytenum, data) do { *WAVERAM_PTR8(base, bytenum) = (data); } while (0) + +#define WAVERAM_PTR16(base, wordnum) ((UINT16 *)(base) + BYTE_XOR_LE(wordnum)) +#define WAVERAM_READ16(base, wordnum) (*WAVERAM_PTR16(base, wordnum)) +#define WAVERAM_WRITE16(base, wordnum, data) do { *WAVERAM_PTR16(base, wordnum) = (data); } while (0) + +#define WAVERAM_PTR32(base, dwordnum) ((UINT32 *)(base) + (dwordnum)) +#define WAVERAM_READ32(base, dwordnum) (*WAVERAM_PTR32(base, dwordnum)) +#define WAVERAM_WRITE32(base, dwordnum, data) do { *WAVERAM_PTR32(base, dwordnum) = (data); } while (0) + +#define PIXYX_TO_DWORDNUM(y, x) (((((y) & 0x1ff) << 8) | (((x) & 0x1fe) >> 1)) * 3 + ((x) & 1)) +#define DEPTHYX_TO_DWORDNUM(y, x) (PIXYX_TO_DWORDNUM(y, (x) & ~1) + 2) + +#define WAVERAM_PTRPIX(base, y, x) WAVERAM_PTR32(base, PIXYX_TO_DWORDNUM(y, x)) +#define WAVERAM_READPIX(base, y, x) (*WAVERAM_PTRPIX(base, y, x)) +#define WAVERAM_WRITEPIX(base, y, x, color) do { *WAVERAM_PTRPIX(base, y, x) = (color); } while (0) + +#define WAVERAM_PTRDEPTH(base, y, x) WAVERAM_PTR16(base, DEPTHYX_TO_DWORDNUM(y, x) * 2 + (x & 1)) +#define WAVERAM_READDEPTH(base, y, x) (*WAVERAM_PTRDEPTH(base, y, x)) +#define WAVERAM_WRITEDEPTH(base, y, x, color) do { *WAVERAM_PTRDEPTH(base, y, x) = (color); } while (0) + +/************************************* +* Polygon renderer +*************************************/ +class zeus2_device; + +class zeus2_renderer : public poly_manager +{ +public: + zeus2_renderer(zeus2_device &state); + + void render_poly_8bit(INT32 scanline, const extent_t& extent, const zeus2_poly_extra_data& object, int threadid); + + void zeus2_draw_quad(const UINT32 *databuffer, UINT32 texoffs, int logit); + +private: + zeus2_device& m_state; +}; +typedef zeus2_renderer::vertex_t poly_vertex; +typedef zeus2_renderer::extent_t poly_extent; + +/************************************* +* Zeus2 Video Device +*************************************/ +#define MCFG_ZEUS2_VBLANK_CB(_devcb) \ + devcb = &zeus2_device::set_vblank_callback(*device, DEVCB_##_devcb); + +#define MCFG_ZEUS2_IRQ_CB(_devcb) \ + devcb = &zeus2_device::set_irq_callback(*device, DEVCB_##_devcb); + +class zeus2_device : public device_t +{ +public: + zeus2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + screen_device *m_screen; /* the screen we are acting on */ + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_READ32_MEMBER( zeus2_r ); + DECLARE_WRITE32_MEMBER( zeus2_w ); + TIMER_CALLBACK_MEMBER(display_irq_off); + TIMER_CALLBACK_MEMBER(display_irq); + + template static devcb_base &set_vblank_callback(device_t &device, _Object object) { return downcast(device).m_vblank.set_callback(object); } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq.set_callback(object); } + devcb_write_line m_vblank; + devcb_write_line m_irq; + + UINT32 m_zeusbase[400]; + + zeus2_renderer* poly; + + void *zeus_renderbase; + rectangle zeus_cliprect; + + float zeus_matrix[3][3]; + float zeus_point[3]; + float zeus_point2[3]; + UINT32 zeus_texbase; + UINT32 zeus_unknown_40; + int zeus_quad_size; + + UINT32 *waveram[2]; + emu_timer *int_timer; + emu_timer *vblank_timer; + int m_yScale; + int yoffs; + int texel_width; + float zbase; + + /************************************* + * Inlines for block addressing + *************************************/ + + inline void *waveram0_ptr_from_expanded_addr(UINT32 addr) + { + UINT32 blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH; + return WAVERAM_BLOCK0(blocknum); + } + + inline void *waveram1_ptr_from_expanded_addr(UINT32 addr) + { + UINT32 blocknum = (addr % WAVERAM1_WIDTH) + ((addr >> 16) % WAVERAM1_HEIGHT) * WAVERAM1_WIDTH; + return WAVERAM_BLOCK1(blocknum); + } + +#ifdef UNUSED_FUNCTION + inline void *waveram0_ptr_from_texture_addr(UINT32 addr, int width) + { + UINT32 blocknum = ((addr & ~1) * width) / 8; + return WAVERAM_BLOCK0(blocknum); + } +#endif + + /************************************* + * Inlines for rendering + *************************************/ + +#ifdef UNUSED_FUNCTION + inline void waveram_plot(int y, int x, UINT32 color) + { + if (zeus_cliprect.contains(x, y)) + WAVERAM_WRITEPIX(zeus_renderbase, y, x, color); + } +#endif + + inline void waveram_plot_depth(int y, int x, UINT32 color, UINT16 depth) + { + if (zeus_cliprect.contains(x, y)) + { + WAVERAM_WRITEPIX(zeus_renderbase, y, x, color); + WAVERAM_WRITEDEPTH(zeus_renderbase, y, x, depth); + } + } + +#ifdef UNUSED_FUNCTION + inline void waveram_plot_check_depth(int y, int x, UINT32 color, UINT16 depth) + { + if (zeus_cliprect.contains(x, y)) + { + UINT16 *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x); + if (depth <= *depthptr) + { + WAVERAM_WRITEPIX(zeus_renderbase, y, x, color); + *depthptr = depth; + } + } + } +#endif + +#ifdef UNUSED_FUNCTION + inline void waveram_plot_check_depth_nowrite(int y, int x, UINT32 color, UINT16 depth) + { + if (zeus_cliprect.contains(x, y)) + { + UINT16 *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x); + if (depth <= *depthptr) + WAVERAM_WRITEPIX(zeus_renderbase, y, x, color); + } + } +#endif + /************************************* + * Inlines for texel accesses + *************************************/ + inline UINT8 get_texel_8bit(const void *base, int y, int x, int width) + { + UINT32 byteoffs = (y / 2) * (width * 2) + ((x / 4) << 3) + ((y & 1) << 2) + (x & 3); + return WAVERAM_READ8(base, byteoffs); + } + +#ifdef UNUSED_FUNCTION + inline UINT8 get_texel_4bit(const void *base, int y, int x, int width) + { + UINT32 byteoffs = (y / 2) * (width * 2) + ((x / 8) << 3) + ((y & 1) << 2) + ((x / 2) & 3); + return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f; + } +#endif + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_stop() override; + +private: + TIMER_CALLBACK_MEMBER(int_timer_callback); + void zeus2_register32_w(offs_t offset, UINT32 data, int logit); + void zeus2_register_update(offs_t offset, UINT32 oldval, int logit); + int zeus2_fifo_process(const UINT32 *data, int numwords); + void zeus2_pointer_write(UINT8 which, UINT32 value); + void zeus2_draw_model(UINT32 baseaddr, UINT16 count, int logit); + void log_fifo_command(const UINT32 *data, int numwords, const char *suffix); + + /************************************* + * Member variables + *************************************/ + + + UINT8 log_fifo; + + UINT32 zeus_fifo[20]; + UINT8 zeus_fifo_words; + +#if TRACK_REG_USAGE + struct reg_info + { + struct reg_info *next; + UINT32 value; + }; + + reg_info *regdata[0x80]; + int regdata_count[0x80]; + int regread_count[0x80]; + int regwrite_count[0x80]; + reg_info *subregdata[0x100]; + int subregdata_count[0x80]; + int subregwrite_count[0x100]; +#endif + + +}; + +// device type definition +extern const device_type ZEUS2; + +#endif diff --git a/src/mame/audio/dcs.cpp b/src/mame/audio/dcs.cpp index 75972ebf0cf..1d28e3fd459 100644 --- a/src/mame/audio/dcs.cpp +++ b/src/mame/audio/dcs.cpp @@ -1872,10 +1872,10 @@ WRITE16_MEMBER(dcs_audio_device:: adsp_control_w ) switch (offset) { case SYSCONTROL_REG: - /* bit 9 forces a reset */ - if (data & 0x0200) + /* bit 9 forces a reset (not on 2181) */ + if ((data & 0x0200) && !(m_rev == 3 || m_rev == 4)) { - logerror("%04X:Rebooting DCS due to SYSCONTROL write\n", space.device().safe_pc()); + logerror("%04X:Rebooting DCS due to SYSCONTROL write = %04X\n", space.device().safe_pc(), data); m_cpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE); dcs_boot(); m_control_regs[SYSCONTROL_REG] = 0; @@ -1950,9 +1950,7 @@ TIMER_DEVICE_CALLBACK_MEMBER( dcs_audio_device::dcs_irq ) { int count = m_size / (2*(m_incs ? m_incs : 1)); // sf2049se was having overflow issues with fixed size of 0x400 buffer (m_size==0xb40, count=0x5a0). - //INT16 buffer[0x400]; - std::unique_ptr buffer; - buffer = std::make_unique(count); + INT16 buffer[0x800]; int i; for (i = 0; i < count; i++) @@ -1962,7 +1960,7 @@ TIMER_DEVICE_CALLBACK_MEMBER( dcs_audio_device::dcs_irq ) } if (m_channels) - dmadac_transfer(&m_dmadac[0], m_channels, 1, m_channels, count / m_channels, buffer.get()); + dmadac_transfer(&m_dmadac[0], m_channels, 1, m_channels, count / m_channels, buffer); } /* check for wrapping */ diff --git a/src/mame/drivers/atlantis.cpp b/src/mame/drivers/atlantis.cpp index 65102eee960..f3df327efd6 100644 --- a/src/mame/drivers/atlantis.cpp +++ b/src/mame/drivers/atlantis.cpp @@ -43,6 +43,7 @@ #include "machine/vrc4373.h" #include "machine/pci9050.h" #include "machine/pci-ide.h" +#include "video/zeus2.h" #include "includes/midzeus.h" #include "includes/midzeus2.h" #include "machine/nvram.h" @@ -62,19 +63,22 @@ // These need more verification #define IOASIC_IRQ_SHIFT 0 +#define GALILEO_IRQ_SHIFT 1 +#define ZEUS_IRQ_SHIFT 2 #define PARALLEL_IRQ_SHIFT 3 #define UART0_SHIFT 4 #define UART1_SHIFT 5 -#define ZEUS_IRQ_SHIFT 2 #define VBLANK_IRQ_SHIFT 7 -#define GALILEO_IRQ_SHIFT 0 /* static interrupts */ #define GALILEO_IRQ_NUM MIPS3_IRQ0 +#define VBLANK_IRQ_NUM MIPS3_IRQ3 #define IDE_IRQ_NUM MIPS3_IRQ4 -#define LOG_RTC (1) -#define LOG_ZEUS (0) +#define LOG_RTC (0) +#define LOG_RED (0) +#define LOG_PORT (0) +#define LOG_IRQ (0) class atlantis_state : public driver_device { @@ -83,6 +87,8 @@ public: : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_screen(*this, "screen"), + m_palette(*this, "palette"), + m_zeus(*this, "zeus2"), m_dcs(*this, "dcs"), m_ioasic(*this, "ioasic"), m_uart0(*this, "uart0"), @@ -95,14 +101,14 @@ public: UINT32 screen_update_mwskins(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); required_device m_maincpu; required_device m_screen; - //required_device m_dcs; - //required_device m_dcs; + optional_device m_palette; + required_device m_zeus; required_device m_dcs; required_device m_ioasic; required_device m_uart0; required_device m_uart1; required_device m_rtc; - UINT8 m_rtc_data[0x800]; + UINT8 m_rtc_data[0x8000]; UINT32 m_last_offset; READ8_MEMBER(cmos_r); @@ -110,22 +116,13 @@ public: DECLARE_WRITE32_MEMBER(cmos_protect_w); DECLARE_READ32_MEMBER(cmos_protect_r); UINT32 m_cmos_write_enabled; + UINT32 m_serial_count; DECLARE_READ32_MEMBER(status_leds_r); DECLARE_WRITE32_MEMBER(status_leds_w); UINT8 m_status_leds; DECLARE_WRITE32_MEMBER(asic_fifo_w); - DECLARE_WRITE32_MEMBER(dcs3_fifo_full_w); - - DECLARE_WRITE32_MEMBER(zeus_w); - DECLARE_READ32_MEMBER(zeus_r); - UINT32 m_zeus_data[0x80]; - - READ8_MEMBER (red_r); - WRITE8_MEMBER(red_w); - UINT8 m_red_data[0x1000]; - int m_red_count; READ32_MEMBER (green_r); WRITE32_MEMBER(green_w); @@ -142,6 +139,8 @@ public: UINT8 board_ctrl[CTRL_SIZE]; void update_asic_irq(); + DECLARE_WRITE_LINE_MEMBER(vblank_irq); + DECLARE_WRITE_LINE_MEMBER(zeus_irq); DECLARE_WRITE_LINE_MEMBER(ide_irq); DECLARE_WRITE_LINE_MEMBER(ioasic_irq); @@ -154,37 +153,6 @@ public: UINT32 m_port_ctrl_reg[0x8]; }; -READ8_MEMBER (atlantis_state::red_r) -{ - UINT8 data = m_red_data[offset]; - logerror("%06X: red_r %08x = %02x\n", machine().device("maincpu")->safe_pc(), offset, data); - m_last_offset = offset | 0x10000; - return data; -} - -WRITE8_MEMBER(atlantis_state::red_w) -{ - COMBINE_DATA(&m_red_data[offset]); - - switch (offset) { - case 0: - // User I/O 0 = Allow write to red[0]. Serial Write Enable? - if (m_user_io_state & 0x1) { - // Data written is shifted by 1 bit each time. Maybe a serial line output? - if (m_red_count == 0) - logerror("%06X: red_w start serial %08x = %02x\n", machine().device("maincpu")->safe_pc(), offset, data); - m_red_count++; - if (m_red_count == 8) - m_red_count = 0; - break; - } // Fall through to default if not enabled - default: - logerror("%06X: red_w %08x = %02x\n", machine().device("maincpu")->safe_pc(), offset, data); - break; - } - m_last_offset = offset | 0x10000; -} - READ32_MEMBER(atlantis_state::green_r) { // If not 0x80 cpu writes to 00e80000 = 0 @@ -222,10 +190,12 @@ READ32_MEMBER(atlantis_state::board_ctrl_r) if (1 && m_screen->vblank()) data |= 0x80; if (m_last_offset != (newOffset | 0x40000)) - logerror("%s:board_ctrl_r read from CTRL_STATUS offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_r read from CTRL_STATUS offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; default: - logerror("%s:board_ctrl_r read from offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_r read from offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; } m_last_offset = newOffset | 0x40000; @@ -251,66 +221,70 @@ WRITE32_MEMBER(atlantis_state::board_ctrl_w) m_dcs->reset_w(CLEAR_LINE); } } - logerror("%s:board_ctrl_w write to CTRL_POWER0 offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_w write to CTRL_POWER0 offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; case CTRL_POWER1: - // 0x1 VBlank clear? + // 0x1 VBlank clear? if (changeData & 0x1) { if ((data & 0x0001) == 0) { + //UINT32 status_bit = (1 << VBLANK_IRQ_SHIFT); + UINT32 status_bit = (1 << 7); + board_ctrl[CTRL_CAUSE] &= ~status_bit; + board_ctrl[CTRL_STATUS] &= ~status_bit; + update_asic_irq(); } else { } } - logerror("%s:board_ctrl_w write to CTRL_POWER1 offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_w write to CTRL_POWER1 offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; case CTRL_GLOBAL_EN: // Zero bit will clear cause board_ctrl[CTRL_CAUSE] &= data; update_asic_irq(); - logerror("%s:board_ctrl_w write to CTRL_GLOBAL_EN offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_w write to CTRL_GLOBAL_EN offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; default: - logerror("%s:board_ctrl_w write to offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); + if (LOG_IRQ) + logerror("%s:board_ctrl_w write to offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); break; } } -WRITE32_MEMBER(atlantis_state::asic_fifo_w) -{ - m_ioasic->fifo_w(data); -} - READ8_MEMBER(atlantis_state::cmos_r) { UINT8 result = m_rtc_data[offset]; switch (offset) { - case 0x7F9: - case 0x7FA: - case 0x7FB: - case 0x7FC: - case 0x7FD: - case 0x7FE: - case 0x7FF: - if ((m_rtc_data[0x7F8] & 0x40)==0) { + case 0x7FF9: + case 0x7FFA: + case 0x7FFB: + case 0x7FFC: + case 0x7FFD: + case 0x7FFE: + case 0x7FFF: + if ((m_rtc_data[0x7FF8] & 0x40)==0) { system_time systime; // get the current date/time from the core machine().current_datetime(systime); - m_rtc_data[0x7F9] = dec_2_bcd(systime.local_time.second); - m_rtc_data[0x7FA] = dec_2_bcd(systime.local_time.minute); - m_rtc_data[0x7FB] = dec_2_bcd(systime.local_time.hour); + m_rtc_data[0x7FF9] = dec_2_bcd(systime.local_time.second); + m_rtc_data[0x7FFA] = dec_2_bcd(systime.local_time.minute); + m_rtc_data[0x7FFB] = dec_2_bcd(systime.local_time.hour); - m_rtc_data[0x7FC] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); - m_rtc_data[0x7FD] = dec_2_bcd(systime.local_time.mday); - m_rtc_data[0x7FE] = dec_2_bcd(systime.local_time.month + 1); - m_rtc_data[0x7FF] = dec_2_bcd(systime.local_time.year - 1900); // Epoch is 1900 + m_rtc_data[0x7FFC] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); + m_rtc_data[0x7FFD] = dec_2_bcd(systime.local_time.mday); + m_rtc_data[0x7FFE] = dec_2_bcd(systime.local_time.month + 1); + m_rtc_data[0x7FFF] = dec_2_bcd(systime.local_time.year - 1900); // Epoch is 1900 result = m_rtc_data[offset]; } break; default: if (LOG_RTC) - logerror("%s:RTC read from offset %04X = %08X m_rtc_data[0x7F8] %02X\n", machine().describe_context(), offset, result, m_rtc_data[0x7F8]); + logerror("%s:RTC read from offset %04X = %08X m_rtc_data[0x7FF8] %02X\n", machine().describe_context(), offset, result, m_rtc_data[0x7FF8]); break; } return result; @@ -319,23 +293,31 @@ READ8_MEMBER(atlantis_state::cmos_r) WRITE8_MEMBER(atlantis_state::cmos_w) { system_time systime; - - if (m_cmos_write_enabled) { + // User I/O 0 = Allow write to cmos[0]. Serial Write Enable? + if (offset == 0 && (m_user_io_state & 0x1)) { + // Data written is shifted by 1 bit each time. Maybe a serial line output? + if (LOG_RTC && m_serial_count == 0) + logerror("%06X: cmos_w[0] start serial %08x = %02x\n", machine().device("maincpu")->safe_pc(), offset, data); + m_serial_count++; + if (m_serial_count == 8) + m_serial_count = 0; + } + else if (m_cmos_write_enabled) { COMBINE_DATA(&m_rtc_data[offset]); m_cmos_write_enabled = FALSE; switch (offset) { - case 0x7F8: // M48T02 time + case 0x7FF8: // M48T02 time if (data & 0x40) { // get the current date/time from the core machine().current_datetime(systime); - m_rtc_data[0x7F9] = dec_2_bcd(systime.local_time.second); - m_rtc_data[0x7FA] = dec_2_bcd(systime.local_time.minute); - m_rtc_data[0x7FB] = dec_2_bcd(systime.local_time.hour); + m_rtc_data[0x7FF9] = dec_2_bcd(systime.local_time.second); + m_rtc_data[0x7FFA] = dec_2_bcd(systime.local_time.minute); + m_rtc_data[0x7FFB] = dec_2_bcd(systime.local_time.hour); - m_rtc_data[0x7FC] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); - m_rtc_data[0x7FD] = dec_2_bcd(systime.local_time.mday); - m_rtc_data[0x7FE] = dec_2_bcd(systime.local_time.month + 1); - m_rtc_data[0x7FF] = dec_2_bcd(systime.local_time.year - 1900); // Epoch is 1900 + m_rtc_data[0x7FFC] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); + m_rtc_data[0x7FFD] = dec_2_bcd(systime.local_time.mday); + m_rtc_data[0x7FFE] = dec_2_bcd(systime.local_time.month + 1); + m_rtc_data[0x7FFF] = dec_2_bcd(systime.local_time.year - 1900); // Epoch is 1900 } if (LOG_RTC) logerror("%s:RTC write to offset %04X = %08X & %08X\n", machine().describe_context(), offset, data, mem_mask); @@ -396,45 +378,14 @@ WRITE32_MEMBER(atlantis_state::status_leds_w) } } -READ32_MEMBER(atlantis_state::zeus_r) -{ - UINT32 result = m_zeus_data[offset]; - switch (offset) { - case 0x1: - /* bit $000C0070 are tested in a loop until 0 */ - /* bits $00080000 is tested in a loop until 0 */ - /* bit $00000004 is tested for toggling; probably VBLANK */ - // zeus is reset if 0x80 is read - //if (m_screen->vblank()) - m_zeus_data[offset] = (m_zeus_data[offset] + 1) & 0xf; - break; - case 0x41: - // CPU resets map2, writes 0xffffffff here, and then expects this read - result &= 0x1fff03ff; - break; - } - if (LOG_ZEUS) - logerror("%s:zeus_r read from offset %04X = %08X & %08X\n", machine().describe_context(), offset, result, mem_mask); - return result; -} - -WRITE32_MEMBER(atlantis_state::zeus_w) -{ - COMBINE_DATA(&m_zeus_data[offset]); - if (LOG_ZEUS) - logerror("%s:zeus_w write to offset %04X = %08X & %08X\n", machine().describe_context(), offset, data, mem_mask); - m_last_offset = offset | 0x30000; -} - - READ32_MEMBER(atlantis_state::cmos_protect_r) { return m_cmos_write_enabled; } -WRITE32_MEMBER(atlantis_state::dcs3_fifo_full_w) +WRITE32_MEMBER(atlantis_state::asic_fifo_w) { - m_ioasic->fifo_full_w(data); + m_ioasic->fifo_w(data); } /************************************* @@ -495,13 +446,49 @@ WRITE_LINE_MEMBER(atlantis_state::uart1_irq_callback) logerror("atlantis_state::uart1_irq_callback state = %1x\n", state); } +/************************************* +* Video interrupts +*************************************/ +WRITE_LINE_MEMBER(atlantis_state::vblank_irq) +{ + //logerror("%s: atlantis_state::vblank state = %i\n", machine().describe_context(), state); + if (1) { + if (state) { + board_ctrl[CTRL_STATUS] |= (1 << VBLANK_IRQ_SHIFT); + update_asic_irq(); + } + else { + board_ctrl[CTRL_STATUS] &= ~(1 << VBLANK_IRQ_SHIFT); + board_ctrl[CTRL_CAUSE] &= ~(1 << VBLANK_IRQ_SHIFT); + update_asic_irq(); + } + } else { + m_maincpu->set_input_line(VBLANK_IRQ_NUM, state); + } +} + +WRITE_LINE_MEMBER(atlantis_state::zeus_irq) +{ + logerror("%s: atlantis_state::zeus_irq state = %i\n", machine().describe_context(), state); + if (state) { + board_ctrl[CTRL_STATUS] |= (1 << ZEUS_IRQ_SHIFT); + update_asic_irq(); + } + else { + board_ctrl[CTRL_STATUS] &= ~(1 << ZEUS_IRQ_SHIFT); + board_ctrl[CTRL_CAUSE] &= ~(1 << ZEUS_IRQ_SHIFT); + update_asic_irq(); + } +} + /************************************* * IDE interrupts *************************************/ WRITE_LINE_MEMBER(atlantis_state::ide_irq) { m_maincpu->set_input_line(IDE_IRQ_NUM, state); - logerror("%s: atlantis_state::ide_irq state = %i\n", machine().describe_context(), state); + if (LOG_IRQ) + logerror("%s: atlantis_state::ide_irq state = %i\n", machine().describe_context(), state); } /************************************* @@ -509,7 +496,8 @@ WRITE_LINE_MEMBER(atlantis_state::ide_irq) *************************************/ WRITE_LINE_MEMBER(atlantis_state::ioasic_irq) { - logerror("%s: atlantis_state::ioasic_irq state = %i\n", machine().describe_context(), state); + if (LOG_IRQ) + logerror("%s: atlantis_state::ioasic_irq state = %i\n", machine().describe_context(), state); if (state) { board_ctrl[CTRL_STATUS] |= (1 << IOASIC_IRQ_SHIFT); update_asic_irq(); @@ -535,13 +523,13 @@ void atlantis_state::update_asic_irq() if (irqBits && !currState) { m_maincpu->set_input_line(MIPS3_IRQ0 + irqIndex, ASSERT_LINE); m_irq_state |= (1 << irqIndex); - if (1) + if (LOG_IRQ) logerror("atlantis_state::update_asic_irq Asserting IRQ(%d) CAUSE = %02X\n", irqIndex, board_ctrl[CTRL_CAUSE]); } else if (!(causeBits) && currState) { m_maincpu->set_input_line(MIPS3_IRQ0 + irqIndex, CLEAR_LINE); m_irq_state &= ~(1 << irqIndex); - if (1) + if (LOG_IRQ) logerror("atlantis_state::update_asic_irq Clearing IRQ(%d) CAUSE = %02X\n", irqIndex, board_ctrl[CTRL_CAUSE]); } } @@ -553,7 +541,8 @@ READ32_MEMBER(atlantis_state::port_ctrl_r) { UINT32 newOffset = offset >> 17; UINT32 result = m_port_ctrl_reg[newOffset]; - logerror("%s: port_ctrl_r newOffset = %02X data = %08X\n", machine().describe_context(), newOffset, result); + if (LOG_PORT) + logerror("%s: port_ctrl_r newOffset = %02X data = %08X\n", machine().describe_context(), newOffset, result); return result; } @@ -562,22 +551,24 @@ WRITE32_MEMBER(atlantis_state::port_ctrl_w) UINT32 newOffset = offset >> 17; COMBINE_DATA(&m_port_ctrl_reg[newOffset]); - switch (newOffset) { - //case 1: - // m_port_ctrl_reg[newOffset] = 0; - // if (!(data & 0x8)) - // m_port_ctrl_reg[newOffset] = 0*3; // Row 0 - // else if (!(data & 0x10)) - // m_port_ctrl_reg[newOffset] = 1*3; // Row 1 - // else if (!(data & 0x20)) - // m_port_ctrl_reg[newOffset] = 2*3; // Row 2 - // else if (!(data & 0x40)) - // m_port_ctrl_reg[newOffset] = 3*3; // Row 3 - // logerror("%s: port_ctrl_w Keypad Row Sel = %04X data = %08X\n", machine().describe_context(), m_port_ctrl_reg[newOffset], data); - // break; - default: - logerror("%s: port_ctrl_w write to offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); - break; + //switch (newOffset) { + if (newOffset == 1) { + UINT32 bits = ioport("KEYPAD")->read(); + m_port_ctrl_reg[2] = 0; + if (!(data & 0x8)) + m_port_ctrl_reg[2] = bits & 7; // Row 0 + else if (!(data & 0x10)) + m_port_ctrl_reg[2] = (bits >> 4) & 7; // Row 1 + else if (!(data & 0x20)) + m_port_ctrl_reg[2] = (bits >> 8) & 7; // Row 2 + else if (!(data & 0x40)) + m_port_ctrl_reg[2] = (bits >> 12) & 7; // Row 3 + if (LOG_PORT) + logerror("%s: port_ctrl_w Keypad Row Sel = %04X bits = %08X\n", machine().describe_context(), data, bits); + } + else { + if (LOG_PORT) + logerror("%s: port_ctrl_w write to offset %04X = %08X & %08X bus offset = %08X\n", machine().describe_context(), newOffset, data, mem_mask, offset); } } @@ -625,24 +616,17 @@ void atlantis_state::machine_reset() m_dcs->reset_w(0); m_user_io_state = 0; m_cmos_write_enabled = FALSE; - memset(m_zeus_data, 0, sizeof(m_zeus_data)); - m_red_count = 0; + m_serial_count = 0; m_irq_state = 0; memset(board_ctrl, 0, sizeof(board_ctrl)); memset(m_port_ctrl_reg, 0, sizeof(m_port_ctrl_reg)); } - - /************************************* - * - * Main CPU memory handlers - * + * Address Maps *************************************/ - static ADDRESS_MAP_START( map0, AS_PROGRAM, 32, atlantis_state ) - AM_RANGE(0x00000000, 0x00000fff) AM_READWRITE8(red_r, red_w, 0xff) - AM_RANGE(0x0001e000, 0x0001ffff) AM_READWRITE8(cmos_r, cmos_w, 0xff) + AM_RANGE(0x00000000, 0x0001ffff) AM_READWRITE8(cmos_r, cmos_w, 0xff) AM_RANGE(0x00100000, 0x0010001f) AM_DEVREADWRITE8("uart0", ns16550_device, ins8250_r, ins8250_w, 0xff) // Serial UART0 (TL16C552 CS0) AM_RANGE(0x00180000, 0x0018001f) AM_DEVREADWRITE8("uart1", ns16550_device, ins8250_r, ins8250_w, 0xff) // Serial UART1 (TL16C552 CS1) //AM_RANGE(0x00200000, 0x0020001f) // Parallel UART (TL16C552 CS2) @@ -665,22 +649,20 @@ ADDRESS_MAP_END static ADDRESS_MAP_START( map1, AS_PROGRAM, 32, atlantis_state ) AM_RANGE(0x00000000, 0x0000003f) AM_DEVREADWRITE("ioasic", midway_ioasic_device, read, write) // asic_fifo_w - // dcs3_fifo_full_w - //AM_RANGE(0x00200000, 0x00200003) + AM_RANGE(0x00200000, 0x00200003) AM_WRITE(asic_fifo_w) AM_RANGE(0x00400000, 0x00400003) AM_DEVWRITE("dcs", dcs_audio_device, dsio_idma_addr_w) AM_RANGE(0x00600000, 0x00600003) AM_DEVREADWRITE("dcs", dcs_audio_device, dsio_idma_data_r, dsio_idma_data_w) - //AM_RANGE(0x00800000, 0x00800003) AM_WRITE(dcs3_fifo_full_w) - //AM_RANGE(0x00800000, 0x00800003) AM_WRITE(asic_fifo_w) - //AM_RANGE(0x00800000, 0x00a00003) AM_READWRITE(port_ctrl_r, port_ctrl_w) + AM_RANGE(0x00800000, 0x00900003) AM_READWRITE(port_ctrl_r, port_ctrl_w) //AM_RANGE(0x00800000, 0x00800003) // Written once = 0000fff8 //AM_RANGE(0x00880000, 0x00880003) // Initial write 0000fff0, follow by sequence ffef, ffdf, ffbf, fff7. Row Select? //AM_RANGE(0x00900000, 0x00900003) // Read once before each sequence write to 0x00880000. Code checks bits 0,1,2. Keypad? //AM_RANGE(0x00980000, 0x00980003) // Read / Write. Bytes written 0x8f, 0xcf. Code if read 0x1 then read 00a00000. POTs? //AM_RANGE(0x00a00000, 0x00a00003) - ADDRESS_MAP_END + AM_RANGE(0x00980000, 0x00980003) AM_NOP // AM_WRITE(asic_fifo_w) +ADDRESS_MAP_END static ADDRESS_MAP_START(map2, AS_PROGRAM, 32, atlantis_state) - AM_RANGE(0x00000000, 0x000001ff) AM_READWRITE(zeus_r, zeus_w) + AM_RANGE(0x00000000, 0x000001ff) AM_DEVREADWRITE("zeus2", zeus2_device, zeus2_r, zeus2_w) ADDRESS_MAP_END static ADDRESS_MAP_START( map3, AS_PROGRAM, 32, atlantis_state ) @@ -696,26 +678,26 @@ ADDRESS_MAP_END static INPUT_PORTS_START( mwskins ) PORT_START("DIPS") PORT_DIPNAME(0x0003, 0x0003, "Boot Mode") - PORT_DIPSETTING(0x0003, "Normal Boot") + PORT_DIPSETTING(0x0003, "Run Game") PORT_DIPSETTING(0x0002, "Boot EEPROM Based Self Test") PORT_DIPSETTING(0x0001, "Boot Disk Based Self Test") PORT_DIPSETTING(0x0000, "Run Factory Tests") - PORT_DIPNAME(0x0004, 0x0004, "Unknown0004") - PORT_DIPSETTING(0x0004, DEF_STR(Off)) - PORT_DIPSETTING(0x0000, DEF_STR(On)) - PORT_DIPNAME(0x0008, 0x0008, "Unknown0008") + PORT_DIPNAME(0x0004, 0x0004, "Boot Message") + PORT_DIPSETTING(0x0004, "Quiet") + PORT_DIPSETTING(0x0000, "Squawk During Boot") + PORT_DIPNAME(0x0008, 0x0008, "Reserved") PORT_DIPSETTING(0x0008, DEF_STR(Off)) PORT_DIPSETTING(0x0000, DEF_STR(On)) - PORT_DIPNAME(0x0010, 0x0010, "Unknown0010") + PORT_DIPNAME(0x0010, 0x0010, "Reserved") PORT_DIPSETTING(0x0010, DEF_STR(Off)) PORT_DIPSETTING(0x0000, DEF_STR(On)) - PORT_DIPNAME(0x0020, 0x0020, "Unknown0020") + PORT_DIPNAME(0x0020, 0x0020, "Reserved") PORT_DIPSETTING(0x0020, DEF_STR(Off)) PORT_DIPSETTING(0x0000, DEF_STR(On)) - PORT_DIPNAME(0x0040, 0x0040, "Unknown0040") + PORT_DIPNAME(0x0040, 0x0040, "Reserved") PORT_DIPSETTING(0x0040, DEF_STR(Off)) PORT_DIPSETTING(0x0000, DEF_STR(On)) - PORT_DIPNAME(0x0080, 0x0080, "Unknown0080") + PORT_DIPNAME(0x0080, 0x0080, "Reserved") PORT_DIPSETTING(0x0080, DEF_STR(Off)) PORT_DIPSETTING(0x0000, DEF_STR(On)) PORT_DIPNAME(0x0100, 0x0100, "Unknown0100") @@ -783,18 +765,18 @@ static INPUT_PORTS_START( mwskins ) PORT_BIT(0xffff, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("KEYPAD") - PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) /* keypad 3 */ - PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) /* keypad 1 */ - PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) /* keypad 2 */ - PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) /* keypad 6 */ - PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) /* keypad 4 */ - PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) /* keypad 5 */ - PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) /* keypad 9 */ - PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) /* keypad 7 */ - PORT_BIT(0x0400, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) /* keypad 8 */ - PORT_BIT(0x1000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad #") PORT_CODE(KEYCODE_PLUS_PAD) /* keypad # */ - PORT_BIT(0x2000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad *") PORT_CODE(KEYCODE_MINUS_PAD) /* keypad * */ - PORT_BIT(0x4000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) /* keypad 0 */ + PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) /* keypad 1 */ + PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) /* keypad 2 */ + PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) /* keypad 3 */ + PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) /* keypad 4 */ + PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) /* keypad 5 */ + PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) /* keypad 6 */ + PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) /* keypad 7 */ + PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) /* keypad 8 */ + PORT_BIT(0x0400, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) /* keypad 9 */ + PORT_BIT(0x1000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad *") PORT_CODE(KEYCODE_MINUS_PAD) /* keypad - */ + PORT_BIT(0x2000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) /* keypad 0 */ + PORT_BIT(0x4000, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_NAME("Keypad #") PORT_CODE(KEYCODE_PLUS_PAD) /* keypad + */ INPUT_PORTS_END @@ -830,16 +812,13 @@ static MACHINE_CONFIG_START( mwskins, atlantis_state ) MCFG_IDE_PCI_IRQ_HANDLER(DEVWRITELINE(":", atlantis_state, ide_irq)) /* video hardware */ - MCFG_SCREEN_ADD("screen", RASTER) - MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) - MCFG_SCREEN_REFRESH_RATE(60) - MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) - MCFG_SCREEN_SIZE(320, 240) - MCFG_SCREEN_VISIBLE_AREA(0, 319, 0, 239) - MCFG_SCREEN_UPDATE_DRIVER(atlantis_state, screen_update_mwskins) - MCFG_SCREEN_PALETTE("palette") + MCFG_DEVICE_ADD("zeus2", ZEUS2, MIDZEUS_VIDEO_CLOCK) + MCFG_ZEUS2_IRQ_CB(WRITELINE(atlantis_state, zeus_irq)) + MCFG_ZEUS2_VBLANK_CB(WRITELINE(atlantis_state, vblank_irq)) - MCFG_PALETTE_ADD_BBBBBGGGGGRRRRR("palette") + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(MIDZEUS_VIDEO_CLOCK / 4, 634, 0, 368, 560, 0, 512) + MCFG_SCREEN_UPDATE_DEVICE("zeus2", zeus2_device, screen_update) /* sound hardware */ //MCFG_DEVICE_ADD("dcs", DCS2_AUDIO_DSIO, 0)