diff options
Diffstat (limited to 'trunk/src/mame/drivers/crystal.c')
-rw-r--r-- | trunk/src/mame/drivers/crystal.c | 1040 |
1 files changed, 1040 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/crystal.c b/trunk/src/mame/drivers/crystal.c new file mode 100644 index 00000000000..80f995dd873 --- /dev/null +++ b/trunk/src/mame/drivers/crystal.c @@ -0,0 +1,1040 @@ +/* + CRYSTAL SYSTEM by Brezzasoft (2001) + using VRender0 System on a Chip + + The VRender0 (info at archive.org for http://www.mesdigital.com) chip contains: + - CPU Core SE3208 (info at www.adc.co.kr) @ 43Mhz + - 2 DMA chans + - 4 Timers + - 32 PIO pins + - PWM output + - 32 channels wavetable synth (8bit linear, 16bit linear and 8bit ulaw sample format) + - Custom 2D video rendering device (texture mapping, alphablend, roz) + + The protection is a PIC deviced labeled SMART-IC in the rom board, I'm not sure how + it exactly works, but it supplies some opcodes that have been replaced with garbage + in the main program. I don't know if it traps reads and returns the correct ones when + reading from flash, or if it's interfaced by the main program after copying the program + from flash to ram and it provides the addresses and values to patch. I patch the flash + program with the correct data + + MAME driver by ElSemi + +The Crystal of Kings +Brezza Soft Corporation (Japan), 2001 + +This game runs on a small cartridge-based PCB known as the 'Crystal System' +There are only two known games running on this system, Crystal of Kings and Evolution Soccer. +The main PCB is small (approx 6" square) and contains only a few components. All of the processing +work is done by the large IC in the middle of the PCB. The system looks a bit like IGS's PGM System, in +that it's housed in a plastic case and has a single slot for insertion of a game cart. However this +system and the game carts are approx. half the size of the PGM carts. +On bootup, the screen is black and the system outputs a vertical white line on the right side of the screen. +The HSync is approx 20kHz, the screen is out of sync on a standard 15kHz arcade monitor. +After approx. 15-20 seconds, the screen changes to white and has some vertical stripes on it and the HSync +changes to 15kHz. After a few more seconds the game boots to a white screen and a blue 'Brezza Soft' logo. +Without a cart plugged in, the screen stays at the first vertical line screen. + +Main PCB Layout +--------------- + +Brezza Soft MAGIC EYES AMG0110B + |----------------------------------------------------| + |TDA1519 VOL 3.6V_BATT SW1 SW2 SW3 | +|-| | +| DS1233 | +| |---| | +| GM76256 | | | +| DA1133A |-----| | | | +| HY57V651620 32.768kHz |MX27L| | | | +| DS1302 |1000 | | | | +|J |-------------| |-----| | | | +|A | |LED1 | | | +|M | |LED2 |CN1| | +|M HY57V651620 | VRENDERZERO | | | | +|A | | | | | +| | | | | | +| |-------------| HY57V651620 | | | +| | | | +| 14.31818MHz | | | +| PAL |---| | +| TD62003 | +|-| | + | |---------------| DSW(8) | + |-| CN2 |----------------------------------| + |---------------| + +Notes: + GM76C256 : Hyundai GM76C256 32k x8 SRAM (SOP28) + MX27L1000 : Macronix MX27L1000QC-12 128k x8 EEPROM (BIOS, PLCC32) + PAL : Atmel ATF16V8-10PC PAL (DIP20) + HY57V651620: Hyundai HY57V651620 4M x16 SDRAM (SSOP54) + DA1311A : Philips DA1311A DAC (SOIC8) + DS1233 : Dallas DS1233 master reset IC (SOIC4) + DS1302 : Dallas DS1302 real time clock IC (DIP8) + VRENDERZERO: MESGraphics VRenderZERO (all-in-one main CPU/graphics/sound, QFP240) + SW1 : Push button reset switch + SW2 : Push button service switch + SW3 : Push button test switch + TDA1519 : Philips TDA1519 dual 6W stereo power amplifier (SIP9) + VOL : Master volume potentiometer + 3.6V_BATT : 3.6 Volt NiCad battery 65mAh (for RTC) + TD62003 : Toshiba TD62003 PNP 50V 0.5A quad darlington switch, for driving coin meters (DIP16) + CN1 : PCI-type slot for extension riser board (for game cart connection at 90 degrees to the main PCB) + CN2 : IDC 34-way flat cable connector (purpose unknown) + VSync : 60Hz + + +Game cart PCB +------------- +Cart sticker: 'THE CRYSTAL OF KINGS BCSV0000' +PCB printing: Brezza Soft MAGIC EYES AMG0111B +|------------------------------| +| | +|PIC16xxx? | +| U8 U7 U6 U5 | +|3.57945Mhz | +| | +| | +| | +| | +|74HC138 | +| U4 U3 U2 U1 | +| | +| | +| | +|-| |-| + |--------------------------| + +Notes: + The cart PCB is single sided and contains only... + 1x 3.579545MHz crystal + 1x 74HC138 logic chip + 1x 18 pin unknown chip (DIP18, surface scratched but it's probably a PIC16xxx, labelled 'dgSMART-PR3 MAGIC EYES') + 3x Intel E28F128J3A 128MBit surface mounted FlashROMs (TSOP56, labelled 'BREZZASOFT BCSV0004Fxx', xx=01, 02, 03) + Note: there are 8 spaces total for FlashROMs. Only U1, U2 & U3 are populated in this cart. + +*/ + +#include "emu.h" +#include "cpu/se3208/se3208.h" +#include "video/vrender0.h" +#include "machine/ds1302.h" +#include "sound/vrender0.h" +#include "machine/nvram.h" + +#define IDLE_LOOP_SPEEDUP + +class crystal_state : public driver_device +{ +public: + crystal_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) , + m_sysregs(*this, "sysregs"), + m_workram(*this, "workram"), + m_vidregs(*this, "vidregs"), + m_textureram(*this, "textureram"), + m_frameram(*this, "frameram"), + m_reset_patch(*this, "reset_patch"){ } + + /* memory pointers */ + required_shared_ptr<UINT32> m_sysregs; + required_shared_ptr<UINT32> m_workram; + required_shared_ptr<UINT32> m_vidregs; + required_shared_ptr<UINT32> m_textureram; + required_shared_ptr<UINT32> m_frameram; + required_shared_ptr<UINT32> m_reset_patch; +// UINT32 * m_nvram; // currently this uses generic nvram handling + +#ifdef IDLE_LOOP_SPEEDUP + UINT8 m_FlipCntRead; +#endif + + UINT32 m_Bank; + UINT8 m_FlipCount; + UINT8 m_IntHigh; + UINT32 m_Timerctrl[4]; + emu_timer *m_Timer[4]; + UINT32 m_FlashCmd; + UINT32 m_PIO; + UINT32 m_DMActrl[2]; + UINT8 m_OldPort4; + + device_t *m_maincpu; + ds1302_device *m_ds1302; + device_t *m_vr0video; + DECLARE_READ32_MEMBER(FlipCount_r); + DECLARE_WRITE32_MEMBER(FlipCount_w); + DECLARE_READ32_MEMBER(Input_r); + DECLARE_WRITE32_MEMBER(IntAck_w); + DECLARE_WRITE32_MEMBER(Banksw_w); + DECLARE_WRITE32_MEMBER(Timer0_w); + DECLARE_READ32_MEMBER(Timer0_r); + DECLARE_WRITE32_MEMBER(Timer1_w); + DECLARE_READ32_MEMBER(Timer1_r); + DECLARE_WRITE32_MEMBER(Timer2_w); + DECLARE_READ32_MEMBER(Timer2_r); + DECLARE_WRITE32_MEMBER(Timer3_w); + DECLARE_READ32_MEMBER(Timer3_r); + DECLARE_READ32_MEMBER(FlashCmd_r); + DECLARE_WRITE32_MEMBER(FlashCmd_w); + DECLARE_READ32_MEMBER(PIO_r); + DECLARE_WRITE32_MEMBER(PIO_w); + DECLARE_READ32_MEMBER(DMA0_r); + DECLARE_WRITE32_MEMBER(DMA0_w); + DECLARE_READ32_MEMBER(DMA1_r); + DECLARE_WRITE32_MEMBER(DMA1_w); +}; + +static void IntReq( running_machine &machine, int num ) +{ + crystal_state *state = machine.driver_data<crystal_state>(); + address_space *space = state->m_maincpu->memory().space(AS_PROGRAM); + UINT32 IntEn = space->read_dword(0x01800c08); + UINT32 IntPend = space->read_dword(0x01800c0c); + if (IntEn & (1 << num)) + { + IntPend |= (1 << num); + space->write_dword(0x01800c0c, IntPend); + device_set_input_line(state->m_maincpu, SE3208_INT, ASSERT_LINE); + } +#ifdef IDLE_LOOP_SPEEDUP + state->m_FlipCntRead = 0; + device_resume(state->m_maincpu, SUSPEND_REASON_SPIN); +#endif +} + +READ32_MEMBER(crystal_state::FlipCount_r) +{ + +#ifdef IDLE_LOOP_SPEEDUP + UINT32 IntPend = space.read_dword(0x01800c0c); + m_FlipCntRead++; + if (m_FlipCntRead >= 16 && !IntPend && m_FlipCount != 0) + device_suspend(m_maincpu, SUSPEND_REASON_SPIN, 1); +#endif + return ((UINT32) m_FlipCount) << 16; +} + +WRITE32_MEMBER(crystal_state::FlipCount_w) +{ + + if (mem_mask & 0x00ff0000) + { + int fc = (data >> 16) & 0xff; + if (fc == 1) + m_FlipCount++; + else if (fc == 0) + m_FlipCount = 0; + } +} + +READ32_MEMBER(crystal_state::Input_r) +{ + + if (offset == 0) + return ioport("P1_P2")->read(); + else if (offset == 1) + return ioport("P3_P4")->read(); + else if( offset == 2) + { + UINT8 Port4 = ioport("SYSTEM")->read(); + if (!(Port4 & 0x10) && ((m_OldPort4 ^ Port4) & 0x10)) //coin buttons trigger IRQs + IntReq(machine(), 12); + if (!(Port4 & 0x20) && ((m_OldPort4 ^ Port4) & 0x20)) + IntReq(machine(), 19); + m_OldPort4 = Port4; + return /*dips*/ioport("DSW")->read() | (Port4 << 16); + } + return 0; +} + +WRITE32_MEMBER(crystal_state::IntAck_w) +{ + UINT32 IntPend = space.read_dword(0x01800c0c); + + if (mem_mask & 0xff) + { + IntPend &= ~(1 << (data & 0x1f)); + space.write_dword(0x01800c0c, IntPend); + if (!IntPend) + device_set_input_line(m_maincpu, SE3208_INT, CLEAR_LINE); + } + if (mem_mask & 0xff00) + m_IntHigh = (data >> 8) & 7; +} + +static IRQ_CALLBACK( icallback ) +{ + crystal_state *state = device->machine().driver_data<crystal_state>(); + address_space *space = device->memory().space(AS_PROGRAM); + UINT32 IntPend = space->read_dword(0x01800c0c); + int i; + + for (i = 0; i < 32; ++i) + { + if (BIT(IntPend, i)) + { + return (state->m_IntHigh << 5) | i; + } + } + return 0; //This should never happen +} + +WRITE32_MEMBER(crystal_state::Banksw_w) +{ + + m_Bank = (data >> 1) & 7; + if (m_Bank <= 2) + membank("bank1")->set_base(machine().root_device().memregion("user1")->base() + m_Bank * 0x1000000); + else + membank("bank1")->set_base(machine().root_device().memregion("user2")->base()); +} + +static TIMER_CALLBACK( Timercb ) +{ + crystal_state *state = machine.driver_data<crystal_state>(); + int which = (int)(FPTR)ptr; + static const int num[] = { 0, 1, 9, 10 }; + + if (!(state->m_Timerctrl[which] & 2)) + state->m_Timerctrl[which] &= ~1; + + IntReq(machine, num[which]); +} + +INLINE void Timer_w( address_space *space, int which, UINT32 data, UINT32 mem_mask ) +{ + crystal_state *state = space->machine().driver_data<crystal_state>(); + + if (((data ^ state->m_Timerctrl[which]) & 1) && (data & 1)) //Timer activate + { + int PD = (data >> 8) & 0xff; + int TCV = space->read_dword(0x01801404 + which * 8); + attotime period = attotime::from_hz(43000000) * ((PD + 1) * (TCV + 1)); + + if (state->m_Timerctrl[which] & 2) + state->m_Timer[which]->adjust(period, 0, period); + else + state->m_Timer[which]->adjust(period); + } + COMBINE_DATA(&state->m_Timerctrl[which]); +} + +WRITE32_MEMBER(crystal_state::Timer0_w) +{ + Timer_w(&space, 0, data, mem_mask); +} + +READ32_MEMBER(crystal_state::Timer0_r) +{ + return m_Timerctrl[0]; +} + +WRITE32_MEMBER(crystal_state::Timer1_w) +{ + Timer_w(&space, 1, data, mem_mask); +} + +READ32_MEMBER(crystal_state::Timer1_r) +{ + return m_Timerctrl[1]; +} + +WRITE32_MEMBER(crystal_state::Timer2_w) +{ + Timer_w(&space, 2, data, mem_mask); +} + +READ32_MEMBER(crystal_state::Timer2_r) +{ + return m_Timerctrl[2]; +} + +WRITE32_MEMBER(crystal_state::Timer3_w) +{ + Timer_w(&space, 3, data, mem_mask); +} + +READ32_MEMBER(crystal_state::Timer3_r) +{ + return m_Timerctrl[3]; +} + +READ32_MEMBER(crystal_state::FlashCmd_r) +{ + + if ((m_FlashCmd & 0xff) == 0xff) + { + if (m_Bank <= 2) + { + UINT32 *ptr = (UINT32*)(machine().root_device().memregion("user1")->base() + m_Bank * 0x1000000); + return ptr[0]; + } + else + return 0xffffffff; + } + if ((m_FlashCmd & 0xff) == 0x90) + { + if (m_Bank <= 2) + return 0x00180089; //Intel 128MBit + else + return 0xffffffff; + } + return 0; +} + +WRITE32_MEMBER(crystal_state::FlashCmd_w) +{ + m_FlashCmd = data; +} + +READ32_MEMBER(crystal_state::PIO_r) +{ + return m_PIO; +} + +WRITE32_MEMBER(crystal_state::PIO_w) +{ + UINT32 RST = data & 0x01000000; + UINT32 CLK = data & 0x02000000; + UINT32 DAT = data & 0x10000000; + + m_ds1302->ce_w(RST ? 1 : 0); + m_ds1302->io_w(DAT ? 1 : 0); + m_ds1302->sclk_w(CLK ? 1 : 0); + + if (m_ds1302->io_r()) + space.write_dword(0x01802008, space.read_dword(0x01802008) | 0x10000000); + else + space.write_dword(0x01802008, space.read_dword(0x01802008) & (~0x10000000)); + + COMBINE_DATA(&m_PIO); +} + +INLINE void DMA_w( address_space *space, int which, UINT32 data, UINT32 mem_mask ) +{ + crystal_state *state = space->machine().driver_data<crystal_state>(); + + if (((data ^ state->m_DMActrl[which]) & (1 << 10)) && (data & (1 << 10))) //DMAOn + { + UINT32 CTR = data; + UINT32 SRC = space->read_dword(0x01800804 + which * 0x10); + UINT32 DST = space->read_dword(0x01800808 + which * 0x10); + UINT32 CNT = space->read_dword(0x0180080C + which * 0x10); + int i; + + if (CTR & 0x2) //32 bits + { + for (i = 0; i < CNT; ++i) + { + UINT32 v = space->read_dword(SRC + i * 4); + space->write_dword(DST + i * 4, v); + } + } + else if (CTR & 0x1) //16 bits + { + for (i = 0; i < CNT; ++i) + { + UINT16 v = space->read_word(SRC + i * 2); + space->write_word(DST + i * 2, v); + } + } + else //8 bits + { + for (i = 0; i < CNT; ++i) + { + UINT8 v = space->read_byte(SRC + i); + space->write_byte(DST + i, v); + } + } + data &= ~(1 << 10); + space->write_dword(0x0180080C + which * 0x10, 0); + IntReq(space->machine(), 7 + which); + } + COMBINE_DATA(&state->m_DMActrl[which]); +} + +READ32_MEMBER(crystal_state::DMA0_r) +{ + return m_DMActrl[0]; +} + +WRITE32_MEMBER(crystal_state::DMA0_w) +{ + DMA_w(&space, 0, data, mem_mask); +} + +READ32_MEMBER(crystal_state::DMA1_r) +{ + return m_DMActrl[1]; +} + +WRITE32_MEMBER(crystal_state::DMA1_w) +{ + DMA_w(&space, 1, data, mem_mask); +} + + +static ADDRESS_MAP_START( crystal_mem, AS_PROGRAM, 32, crystal_state ) + AM_RANGE(0x00000000, 0x0001ffff) AM_ROM AM_WRITENOP + + AM_RANGE(0x01200000, 0x0120000f) AM_READ(Input_r) + AM_RANGE(0x01280000, 0x01280003) AM_WRITE(Banksw_w) + AM_RANGE(0x01400000, 0x0140ffff) AM_RAM AM_SHARE("nvram") + + AM_RANGE(0x01801400, 0x01801403) AM_READWRITE(Timer0_r, Timer0_w) + AM_RANGE(0x01801408, 0x0180140b) AM_READWRITE(Timer1_r, Timer1_w) + AM_RANGE(0x01801410, 0x01801413) AM_READWRITE(Timer2_r, Timer2_w) + AM_RANGE(0x01801418, 0x0180141b) AM_READWRITE(Timer3_r, Timer3_w) + AM_RANGE(0x01802004, 0x01802007) AM_READWRITE(PIO_r, PIO_w) + + AM_RANGE(0x01800800, 0x01800803) AM_READWRITE(DMA0_r, DMA0_w) + AM_RANGE(0x01800810, 0x01800813) AM_READWRITE(DMA1_r, DMA1_w) + + AM_RANGE(0x01800c04, 0x01800c07) AM_WRITE(IntAck_w) + AM_RANGE(0x01800000, 0x0180ffff) AM_RAM AM_SHARE("sysregs") + AM_RANGE(0x02000000, 0x027fffff) AM_RAM AM_SHARE("workram") + + AM_RANGE(0x030000a4, 0x030000a7) AM_READWRITE(FlipCount_r, FlipCount_w) + + AM_RANGE(0x03000000, 0x0300ffff) AM_RAM AM_SHARE("vidregs") + AM_RANGE(0x03800000, 0x03ffffff) AM_RAM AM_SHARE("textureram") + AM_RANGE(0x04000000, 0x047fffff) AM_RAM AM_SHARE("frameram") + AM_RANGE(0x04800000, 0x04800fff) AM_DEVREADWRITE_LEGACY("vrender", vr0_snd_read, vr0_snd_write) + + AM_RANGE(0x05000000, 0x05000003) AM_READWRITE(FlashCmd_r, FlashCmd_w) + AM_RANGE(0x05000000, 0x05ffffff) AM_ROMBANK("bank1") + + AM_RANGE(0x44414F4C, 0x44414F7F) AM_RAM AM_SHARE("reset_patch") + +ADDRESS_MAP_END + +static void PatchReset( running_machine &machine ) +{ + //The test menu reset routine seems buggy + //it reads the reset vector from 0x02000000 but it should be + //read from 0x00000000. At 0x2000000 there is the bios signature + //"LOADED VER....", so it jumps to "LOAD" in hex (0x44414F4C) + //I'll add some code there that makes the game stay in a loop + //reading the flip register so the idle skip works + +/* +Loop1: + LDI 1,%R2 + LDI 0x30000a6,%R1 + STS %R2,(%R1,0x0) + +loop: + LDI 0x30000a6,%R1 + LDSU (%R1,0x0),%R2 + CMP %R2,0x0000 + JNZ loop + + JMP Loop1 +*/ + + crystal_state *state = machine.driver_data<crystal_state>(); + +#if 1 + static const UINT32 Patch[] = + { + 0x40c0ea01, + 0xe906400a, + 0x40c02a20, + 0xe906400a, + 0xa1d03a20, + 0xdef4d4fa + }; + + memcpy(state->m_reset_patch, Patch, sizeof(Patch)); +#else + static const UINT8 Patch[] = + { + 0x01,0xEA,0xC0,0x40,0x0A,0x40,0x06,0xE9, + 0x20,0x2A,0xC0,0x40,0x0A,0x40,0x06,0xE9, + 0x20,0x3A,0xD0,0xA1,0xFA,0xD4,0xF4,0xDE + }; + + memcpy(state->m_reset_patch, Patch, sizeof(Patch)); +#endif +} + +static void crystal_banksw_postload(running_machine &machine) +{ + crystal_state *state = machine.driver_data<crystal_state>(); + + if (state->m_Bank <= 2) + state->membank("bank1")->set_base(state->memregion("user1")->base() + state->m_Bank * 0x1000000); + else + state->membank("bank1")->set_base(state->memregion("user2")->base()); +} + +static MACHINE_START( crystal ) +{ + crystal_state *state = machine.driver_data<crystal_state>(); + int i; + + state->m_maincpu = machine.device("maincpu"); + state->m_ds1302 = machine.device<ds1302_device>("rtc"); + state->m_vr0video = machine.device("vr0"); + + device_set_irq_callback(machine.device("maincpu"), icallback); + for (i = 0; i < 4; i++) + state->m_Timer[i] = machine.scheduler().timer_alloc(FUNC(Timercb), (void*)(FPTR)i); + + PatchReset(machine); + +#ifdef IDLE_LOOP_SPEEDUP + state->save_item(NAME(state->m_FlipCntRead)); +#endif + + state->save_item(NAME(state->m_Bank)); + state->save_item(NAME(state->m_FlipCount)); + state->save_item(NAME(state->m_IntHigh)); + state->save_item(NAME(state->m_Timerctrl)); + state->save_item(NAME(state->m_FlashCmd)); + state->save_item(NAME(state->m_PIO)); + state->save_item(NAME(state->m_DMActrl)); + state->save_item(NAME(state->m_OldPort4)); + machine.save().register_postload(save_prepost_delegate(FUNC(crystal_banksw_postload), &machine)); +} + +static MACHINE_RESET( crystal ) +{ + crystal_state *state = machine.driver_data<crystal_state>(); + int i; + + memset(state->m_sysregs, 0, 0x10000); + memset(state->m_vidregs, 0, 0x10000); + state->m_FlipCount = 0; + state->m_IntHigh = 0; + device_set_irq_callback(machine.device("maincpu"), icallback); + state->m_Bank = 0; + state->membank("bank1")->set_base(state->memregion("user1")->base() + 0); + state->m_FlashCmd = 0xff; + state->m_OldPort4 = 0; + + state->m_DMActrl[0] = 0; + state->m_DMActrl[1] = 0; + + for (i = 0; i < 4; i++) + { + state->m_Timerctrl[i] = 0; + state->m_Timer[i]->adjust(attotime::never); + } + + vr0_snd_set_areas(machine.device("vrender"), state->m_textureram, state->m_frameram); +#ifdef IDLE_LOOP_SPEEDUP + state->m_FlipCntRead = 0; +#endif + + PatchReset(machine); +} + +static UINT16 GetVidReg( address_space *space, UINT16 reg ) +{ + return space->read_word(0x03000000 + reg); +} + +static void SetVidReg( address_space *space, UINT16 reg, UINT16 val ) +{ + space->write_word(0x03000000 + reg, val); +} + + +static SCREEN_UPDATE_IND16( crystal ) +{ + crystal_state *state = screen.machine().driver_data<crystal_state>(); + address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM); + int DoFlip; + + UINT32 B0 = 0x0; + UINT32 B1 = (GetVidReg(space, 0x90) & 0x8000) ? 0x400000 : 0x100000; + UINT16 *Front, *Back; + UINT16 *Visible, *DrawDest; + UINT16 *srcline; + int y; + UINT16 head, tail; + UINT32 width = screen.width(); + + if (GetVidReg(space, 0x8e) & 1) + { + Front = (UINT16*) (state->m_frameram + B1 / 4); + Back = (UINT16*) (state->m_frameram + B0 / 4); + } + else + { + Front = (UINT16*) (state->m_frameram + B0 / 4); + Back = (UINT16*) (state->m_frameram + B1 / 4); + } + + Visible = (UINT16*) Front; + // ERROR: This cast is NOT endian-safe without the use of BYTE/WORD/DWORD_XOR_* macros! + DrawDest = reinterpret_cast<UINT16 *>(state->m_frameram.target()); + + + if (GetVidReg(space, 0x8c) & 0x80) + DrawDest = Front; + else + DrawDest = Back; + +// DrawDest = Visible; + + srcline = (UINT16 *) DrawDest; + + DoFlip = 0; + head = GetVidReg(space, 0x82); + tail = GetVidReg(space, 0x80); + while ((head & 0x7ff) != (tail & 0x7ff)) + { + // ERROR: This cast is NOT endian-safe without the use of BYTE/WORD/DWORD_XOR_* macros! + DoFlip = vrender0_ProcessPacket(state->m_vr0video, 0x03800000 + head * 64, DrawDest, reinterpret_cast<UINT8*>(state->m_textureram.target())); + head++; + head &= 0x7ff; + if (DoFlip) + break; + } + + if (DoFlip) + SetVidReg(space, 0x8e, GetVidReg(space, 0x8e) ^ 1); + + srcline = (UINT16 *) Visible; + for (y = 0; y < 240; y++) + memcpy(&bitmap.pix16(y), &srcline[y * 512], width * 2); + + return 0; +} + +static SCREEN_VBLANK(crystal) +{ + // rising edge + if (vblank_on) + { + crystal_state *state = screen.machine().driver_data<crystal_state>(); + address_space *space = screen.machine().device("maincpu")->memory().space(AS_PROGRAM); + UINT16 head, tail; + int DoFlip = 0; + + head = GetVidReg(space, 0x82); + tail = GetVidReg(space, 0x80); + while ((head & 0x7ff) != (tail & 0x7ff)) + { + UINT16 Packet0 = space->read_word(0x03800000 + head * 64); + if (Packet0 & 0x81) + DoFlip = 1; + head++; + head &= 0x7ff; + if (DoFlip) + break; + } + SetVidReg(space, 0x82, head); + if (DoFlip) + { + if (state->m_FlipCount) + state->m_FlipCount--; + + } + } +} + +static INTERRUPT_GEN(crystal_interrupt) +{ + IntReq(device->machine(), 24); //VRender0 VBlank +} + +static INPUT_PORTS_START(crystal) + PORT_START("P1_P2") + PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) + PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) + PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) + PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) + PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) + PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) + PORT_BIT( 0x0000ff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) + PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) + PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) + PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) + PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) + PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) + PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) + PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) + PORT_BIT( 0xff000000, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_START("P3_P4") + PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3) + PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4) + PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3) + PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4) + PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3) + PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4) + PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(3) + PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(4) + PORT_BIT( 0x0000ff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) + PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) + PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) + PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) + PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) + PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) + PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) + PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) + PORT_BIT( 0xff000000, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_START("SYSTEM") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START3 ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START4 ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN2 ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 ) + PORT_SERVICE_NO_TOGGLE( 0x80, IP_ACTIVE_LOW ) + + PORT_START("DSW") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Pause ) ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Free_Play ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Test ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END + +static const vr0_interface vr0_config = +{ + 0x04800000 +}; + +static const vr0video_interface vr0video_config = +{ + "maincpu" +}; + +static MACHINE_CONFIG_START( crystal, crystal_state ) + + MCFG_CPU_ADD("maincpu", SE3208, 43000000) + MCFG_CPU_PROGRAM_MAP(crystal_mem) + MCFG_CPU_VBLANK_INT("screen", crystal_interrupt) + + MCFG_MACHINE_START(crystal) + MCFG_MACHINE_RESET(crystal) + + MCFG_NVRAM_ADD_0FILL("nvram") + + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) + MCFG_SCREEN_SIZE(320, 240) + MCFG_SCREEN_VISIBLE_AREA(0, 319, 0, 239) + MCFG_SCREEN_UPDATE_STATIC(crystal) + MCFG_SCREEN_VBLANK_STATIC(crystal) + + MCFG_VIDEO_VRENDER0_ADD("vr0", vr0video_config) + + MCFG_PALETTE_INIT(RRRRR_GGGGGG_BBBBB) + MCFG_PALETTE_LENGTH(65536) + + MCFG_DS1302_ADD("rtc", XTAL_32_768kHz) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_SOUND_ADD("vrender", VRENDER0, 0) + MCFG_SOUND_CONFIG(vr0_config) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) +MACHINE_CONFIG_END + +/* + Top blade screen is 32 pixels wider +*/ +static MACHINE_CONFIG_DERIVED( topbladv, crystal ) + + MCFG_SCREEN_MODIFY("screen") + MCFG_SCREEN_SIZE(320+32, 240) + MCFG_SCREEN_VISIBLE_AREA(0, 319+32, 0, 239) + +MACHINE_CONFIG_END + +ROM_START( crysbios ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios + ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb) ) + + ROM_REGION32_LE( 0x3000000, "user1", ROMREGION_ERASEFF ) // Flash + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + +ROM_START( crysking ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios + ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb)) + + ROM_REGION32_LE( 0x3000000, "user1", 0 ) // Flash + ROM_LOAD("bcsv0004f01.u1", 0x0000000, 0x1000000, CRC(8FEFF120) SHA1(2ea42fa893bff845b5b855e2556789f8354e9066) ) + ROM_LOAD("bcsv0004f02.u2", 0x1000000, 0x1000000, CRC(0E799845) SHA1(419674ce043cb1efb18303f4cb7fdbbae642ee39) ) + ROM_LOAD("bcsv0004f03.u3", 0x2000000, 0x1000000, CRC(659E2D17) SHA1(342c98f3f695ef4dea8b533612451c4d2fb58809) ) + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + +ROM_START( evosocc ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios + ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb)) + + ROM_REGION32_LE( 0x3000000, "user1", 0 ) // Flash + ROM_LOAD("bcsv0001u01", 0x0000000, 0x1000000, CRC(2581A0EA) SHA1(ee483ac60a3ed00a21cb515974cec4af19916a7d) ) + ROM_LOAD("bcsv0001u02", 0x1000000, 0x1000000, CRC(47EF1794) SHA1(f573706c17d1342b9b7aed9b40b8b648f0bf58db) ) + ROM_LOAD("bcsv0001u03", 0x2000000, 0x1000000, CRC(F396A2EC) SHA1(f305eb10856fb5d4c229a6b09d6a2fb21b24ce66) ) + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + +ROM_START( topbladv ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios + ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb)) + + ROM_REGION( 0x4300, "pic", 0 ) // pic16c727 - we don't have a core for this + ROM_LOAD("top_blade_v_pic16c727.bin", 0x000000, 0x4300, CRC(9cdea57b) SHA1(884156085f9e780cdf719aedc2e8a0fd5983613b) ) + + + ROM_REGION32_LE( 0x1000000, "user1", 0 ) // Flash + ROM_LOAD("flash.u1", 0x0000000, 0x1000000, CRC(bd23f640) SHA1(1d22aa2c828642bb7c1dfea4e13f777f95acc701) ) + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + + +ROM_START( officeye ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios (not the standard one) + ROM_LOAD("bios.u14", 0x000000, 0x020000, CRC(ffc57e90) SHA1(6b6a17fd4798dea9c7b880f3063be8494e7db302) ) + + ROM_REGION( 0x4280, "pic", 0 ) // pic16f84a - we don't have a core for this + ROM_LOAD("office_yeo_in_cheon_ha_pic16f84a.bin", 0x000000, 0x4280, CRC(7561cdf5) SHA1(eade592823a110019b4af81a7dc56d01f7d6589f) ) + + + ROM_REGION32_LE( 0x2000000, "user1", 0 ) // Flash + ROM_LOAD("flash.u1", 0x0000000, 0x1000000, CRC(d3f3eec4) SHA1(ea728415bd4906964b7d37f4379a8a3bd42a1c2d) ) + ROM_LOAD("flash.u2", 0x1000000, 0x1000000, CRC(e4f85d0a) SHA1(2ddfa6b3a30e69754aa9d96434ff3d37784bfa57) ) + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + + +ROM_START( donghaer ) + ROM_REGION( 0x20000, "maincpu", 0 ) // bios + ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb)) + + ROM_REGION( 0x4280, "pic", 0 ) // pic16f84a - we don't have a core for this (or the dump in this case) + ROM_LOAD("donghaer_pic16f84a.bin", 0x000000, 0x4280, NO_DUMP ) + + ROM_REGION32_LE( 0x2000000, "user1", 0 ) // Flash + ROM_LOAD( "u1", 0x0000000, 0x1000000, CRC(61217ad7) SHA1(2593f1356aa850f4f9aa5d00bec822aa59c59224) ) + ROM_LOAD( "u2", 0x1000000, 0x1000000, CRC(6d82f1a5) SHA1(036bd45f0daac1ffeaa5ad9774fc1b56e3c75ff9) ) + + ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash +ROM_END + +static DRIVER_INIT(crysking) +{ + UINT16 *Rom = (UINT16*) machine.root_device().memregion("user1")->base(); + + //patch the data feed by the protection + + Rom[WORD_XOR_LE(0x7bb6/2)] = 0xDF01; + Rom[WORD_XOR_LE(0x7bb8/2)] = 0x9C00; + + Rom[WORD_XOR_LE(0x976a/2)] = 0x901C; + Rom[WORD_XOR_LE(0x976c/2)] = 0x9001; + + Rom[WORD_XOR_LE(0x8096/2)] = 0x90FC; + Rom[WORD_XOR_LE(0x8098/2)] = 0x9001; + + Rom[WORD_XOR_LE(0x8a52/2)] = 0x4000; //NOP + Rom[WORD_XOR_LE(0x8a54/2)] = 0x403c; //NOP +} + +static DRIVER_INIT(evosocc) +{ + UINT16 *Rom = (UINT16*) machine.root_device().memregion("user1")->base(); + Rom += 0x1000000 * 2 / 2; + + Rom[WORD_XOR_LE(0x97388E/2)] = 0x90FC; //PUSH R2..R7 + Rom[WORD_XOR_LE(0x973890/2)] = 0x9001; //PUSH R0 + + Rom[WORD_XOR_LE(0x971058/2)] = 0x907C; //PUSH R2..R6 + Rom[WORD_XOR_LE(0x971060/2)] = 0x9001; //PUSH R0 + + Rom[WORD_XOR_LE(0x978036/2)] = 0x900C; //PUSH R2-R3 + Rom[WORD_XOR_LE(0x978038/2)] = 0x8303; //LD (%SP,0xC),R3 + + Rom[WORD_XOR_LE(0x974ED0/2)] = 0x90FC; //PUSH R7-R6-R5-R4-R3-R2 + Rom[WORD_XOR_LE(0x974ED2/2)] = 0x9001; //PUSH R0 +} + +static DRIVER_INIT(topbladv) +{ + UINT16 *Rom = (UINT16*) machine.root_device().memregion("user1")->base(); + + Rom[WORD_XOR_LE(0x12d7a/2)] = 0x90FC; //PUSH R7-R6-R5-R4-R3-R2 + Rom[WORD_XOR_LE(0x12d7c/2)] = 0x9001; //PUSH R0 + + Rom[WORD_XOR_LE(0x2fe18/2)] = 0x9001; //PUSH R0 + Rom[WORD_XOR_LE(0x2fe1a/2)] = 0x9200; //PUSH SR + + Rom[WORD_XOR_LE(0x18880/2)] = 0x9001; //PUSH R0 + Rom[WORD_XOR_LE(0x18882/2)] = 0x9200; //PUSH SR + + Rom[WORD_XOR_LE(0xDACE/2)] = 0x901C; //PUSH R4-R3-R2 + Rom[WORD_XOR_LE(0xDAD0/2)] = 0x9001; //PUSH R0 + +} + +static DRIVER_INIT(officeye) +{ + UINT16 *Rom = (UINT16*) machine.root_device().memregion("user1")->base(); + + Rom[WORD_XOR_LE(0x9c9e/2)] = 0x901C; //PUSH R4-R3-R2 + Rom[WORD_XOR_LE(0x9ca0/2)] = 0x9001; //PUSH R0 + + Rom[WORD_XOR_LE(0x9EE4/2)] = 0x907C; //PUSH R6-R5-R4-R3-R2 + Rom[WORD_XOR_LE(0x9EE6/2)] = 0x9001; //PUSH R0 + + Rom[WORD_XOR_LE(0x4B2E0/2)] = 0x9004; //PUSH R2 + Rom[WORD_XOR_LE(0x4B2E2/2)] = 0x9001; //PUSH R0 + +/* + Rom[WORD_XOR_LE(0x18880/2)] = 0x9001; //PUSH R0 + Rom[WORD_XOR_LE(0x18882/2)] = 0x9200; //PUSH SR + */ +} + + + +GAME( 2001, crysbios, 0, crystal, crystal, 0, ROT0, "BrezzaSoft", "Crystal System BIOS", GAME_IS_BIOS_ROOT ) +GAME( 2001, crysking, crysbios, crystal, crystal, crysking, ROT0, "BrezzaSoft", "The Crystal of Kings", 0 ) +GAME( 2001, evosocc, crysbios, crystal, crystal, evosocc, ROT0, "Evoga", "Evolution Soccer", 0 ) +GAME( 2003, topbladv, crysbios, topbladv, crystal, topbladv, ROT0, "SonoKong / Expotato", "Top Blade V", GAME_NOT_WORKING ) // protection +GAME( 2001, officeye, 0, crystal, crystal, officeye, ROT0, "Danbi", "Office Yeo In Cheon Ha (version 1.2)", GAME_NOT_WORKING ) // protection +GAME( 2001, donghaer, 0, crystal, crystal, officeye, ROT0, "Danbi", "Donggul Donggul Haerong", GAME_NOT_WORKING ) |