summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/crystal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/crystal.c')
-rw-r--r--src/mame/drivers/crystal.c926
1 files changed, 926 insertions, 0 deletions
diff --git a/src/mame/drivers/crystal.c b/src/mame/drivers/crystal.c
new file mode 100644
index 00000000000..bb83c0fd672
--- /dev/null
+++ b/src/mame/drivers/crystal.c
@@ -0,0 +1,926 @@
+/*
+ CRYSTAL SYSTEM by Brezzasoft (2001)
+ using VRender0 System on a Chip
+
+ The VRender0 (http://www.mesdigital.com/english/Products/product_vrender0.asp) 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 "driver.h"
+#include "cpu/se3208/se3208.h"
+#include "video/vrender0.h"
+#include "machine/ds1302.h"
+#include "sound/vrender0.h"
+
+#define IDLE_LOOP_SPEEDUP
+
+#ifdef IDLE_LOOP_SPEEDUP
+static UINT8 FlipCntRead;
+#endif
+
+static UINT32 *workram,*textureram,*frameram;
+static UINT32 *sysregs,*vidregs;
+static UINT32 Bank;
+static UINT8 FlipCount,IntHigh;
+static UINT32 Timer0ctrl,Timer1ctrl,Timer2ctrl,Timer3ctrl;
+static void *Timer0,*Timer1,*Timer2,*Timer3;
+static UINT32 FlashCmd,PIO;
+static UINT32 DMA0ctrl,DMA1ctrl;
+static UINT8 OldPort4;
+static UINT32 *ResetPatch;
+
+static void IntReq(int num)
+{
+ UINT32 IntEn=program_read_dword_32le(0x01800c08);
+ UINT32 IntPend=program_read_dword_32le(0x01800c0c);
+ if(IntEn&(1<<num))
+ {
+ IntPend|=(1<<num);
+ program_write_dword_32le(0x01800c0c,IntPend);
+ cpunum_set_input_line(0,SE3208_INT,ASSERT_LINE);
+ }
+#ifdef IDLE_LOOP_SPEEDUP
+ FlipCntRead=0;
+ cpunum_resume(0,SUSPEND_REASON_SPIN);
+#endif
+}
+
+static READ32_HANDLER(FlipCount_r)
+{
+#ifdef IDLE_LOOP_SPEEDUP
+ UINT32 IntPend=program_read_dword_32le(0x01800c0c);
+ FlipCntRead++;
+ if(FlipCntRead>=16 && !IntPend && FlipCount!=0)
+ cpunum_suspend(0,SUSPEND_REASON_SPIN,1);
+#endif
+ return ((UINT32) FlipCount)<<16;
+}
+
+static WRITE32_HANDLER(FlipCount_w)
+{
+ if((~mem_mask)&0x00ff0000)
+ {
+ int fc=(data>>16)&0xff;
+ if(fc==1)
+ FlipCount++;
+ else if(fc==0)
+ FlipCount=0;
+ }
+}
+
+static READ32_HANDLER(Input_r)
+{
+ if(offset==0)
+ return readinputport(0)|(readinputport(1)<<16);
+ else if(offset==1)
+ return readinputport(2)|(readinputport(3)<<16);
+ else if(offset==2)
+ {
+ UINT8 Port4=readinputport(4);
+ if(!(Port4&0x10) && ((OldPort4^Port4)&0x10)) //coin buttons trigger IRQs
+ IntReq(12);
+ if(!(Port4&0x20) && ((OldPort4^Port4)&0x20))
+ IntReq(19);
+ OldPort4=Port4;
+ return /*dips*/readinputport(5)|(Port4<<16);
+ }
+ return 0;
+}
+
+static WRITE32_HANDLER(IntAck_w)
+{
+ UINT32 IntPend=program_read_dword_32le(0x01800c0c);
+ if((~mem_mask)&0xff)
+ {
+ IntPend&=~(1<<(data&0x1f));
+ program_write_dword_32le(0x01800c0c,IntPend);
+ if(!IntPend)
+ cpunum_set_input_line(0,SE3208_INT,CLEAR_LINE);
+ }
+ if((~mem_mask)&0xff00)
+ IntHigh=(data>>8)&7;
+}
+
+static int icallback(int line)
+{
+ int i;
+ UINT32 IntPend=program_read_dword_32le(0x01800c0c);
+
+ for(i=0;i<32;++i)
+ {
+ if(IntPend&(1<<i))
+ {
+ return (IntHigh<<5)|i;
+ break;
+ }
+ }
+ return 0; //This should never happen
+}
+
+static WRITE32_HANDLER(Banksw_w)
+{
+ Bank=(data>>1)&7;
+ if(Bank<=2)
+ memory_set_bankptr(1,memory_region(REGION_USER1)+Bank*0x1000000);
+ else
+ memory_set_bankptr(1,memory_region(REGION_USER2));
+}
+
+static TIMER_CALLBACK( Timer0cb )
+{
+ if(!(Timer0ctrl&2))
+ Timer0ctrl&=~1;
+ IntReq(0);
+}
+
+static WRITE32_HANDLER(Timer0_w)
+{
+ if(((data^Timer0ctrl)&1) && (data&1)) //Timer activate
+ {
+ int PD=(data>>8)&0xff;
+ int TCV=program_read_dword_32le(0x01801404);
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(43000000), (PD + 1) * (TCV + 1));
+
+ if(Timer0ctrl&2)
+ timer_adjust(Timer0,period,0,period);
+ else
+ timer_adjust(Timer0,period,0,attotime_zero);
+ }
+ COMBINE_DATA(&Timer0ctrl);
+}
+
+static READ32_HANDLER(Timer0_r)
+{
+ return Timer0ctrl;
+}
+
+static TIMER_CALLBACK( Timer1cb )
+{
+ if(!(Timer1ctrl&2))
+ Timer1ctrl&=~1;
+ IntReq(1);
+}
+
+static WRITE32_HANDLER(Timer1_w)
+{
+ if(((data^Timer1ctrl)&1) && (data&1)) //Timer activate
+ {
+ int PD=(data>>8)&0xff;
+ int TCV=program_read_dword_32le(0x0180140C);
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(43000000), (PD + 1) * (TCV + 1));
+
+ if(Timer1ctrl&2)
+ timer_adjust(Timer1,period,0,period);
+ else
+ timer_adjust(Timer1,period,0,attotime_zero);
+ }
+ COMBINE_DATA(&Timer1ctrl);
+}
+
+static READ32_HANDLER(Timer1_r)
+{
+ return Timer1ctrl;
+}
+
+static TIMER_CALLBACK( Timer2cb )
+{
+ if(!(Timer2ctrl&2))
+ Timer2ctrl&=~1;
+ IntReq(9);
+}
+
+static WRITE32_HANDLER(Timer2_w)
+{
+ if(((data^Timer2ctrl)&1) && (data&1)) //Timer activate
+ {
+ int PD=(data>>8)&0xff;
+ int TCV=program_read_dword_32le(0x01801414);
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(43000000), (PD + 1) * (TCV + 1));
+
+ if(Timer2ctrl&2)
+ timer_adjust(Timer2,period,0,period);
+ else
+ timer_adjust(Timer2,period,0,attotime_zero);
+ }
+ COMBINE_DATA(&Timer2ctrl);
+}
+
+static READ32_HANDLER(Timer2_r)
+{
+ return Timer2ctrl;
+}
+
+static TIMER_CALLBACK( Timer3cb )
+{
+ if(!(Timer3ctrl&2))
+ Timer3ctrl&=~1;
+ IntReq(10);
+}
+
+static WRITE32_HANDLER(Timer3_w)
+{
+ if(((data^Timer3ctrl)&1) && (data&1)) //Timer activate
+ {
+ int PD=(data>>8)&0xff;
+ int TCV=program_read_dword_32le(0x0180141C);
+ attotime period = attotime_mul(ATTOTIME_IN_HZ(43000000), (PD + 1) * (TCV + 1));
+
+ if(Timer3ctrl&2)
+ timer_adjust(Timer3,period,0,period);
+ else
+ timer_adjust(Timer3,period,0,attotime_zero);
+ }
+ COMBINE_DATA(&Timer3ctrl);
+}
+
+static READ32_HANDLER(Timer3_r)
+{
+ return Timer3ctrl;
+}
+
+static READ32_HANDLER(FlashCmd_r)
+{
+ if((FlashCmd&0xff)==0xff)
+ {
+ if(Bank<=2)
+ {
+ UINT32 *ptr=(UINT32*)(memory_region(REGION_USER1)+Bank*0x1000000);
+ return ptr[0];
+ }
+ else
+ return 0xffffffff;
+ }
+ if((FlashCmd&0xff)==0x90)
+ {
+ if(Bank<=2)
+ return 0x00180089; //Intel 128MBit
+ else
+ return 0xffffffff;
+ }
+ return 0;
+}
+
+static WRITE32_HANDLER(FlashCmd_w)
+{
+ FlashCmd=data;
+}
+
+static READ32_HANDLER(PIO_r)
+{
+ return PIO;
+}
+
+static WRITE32_HANDLER(PIO_w)
+{
+ UINT32 RST=data&0x01000000;
+ UINT32 CLK=data&0x02000000;
+ UINT32 DAT=data&0x10000000;
+
+ DS1302_RST(RST?1:0);
+ DS1302_DAT(DAT?1:0);
+ DS1302_CLK(CLK?1:0);
+
+ if(DS1302_RD())
+ program_write_dword_32le(0x01802008,program_read_dword_32le(0x01802008)|0x10000000);
+ else
+ program_write_dword_32le(0x01802008,program_read_dword_32le(0x01802008)&(~0x10000000));
+
+ COMBINE_DATA(&PIO);
+}
+
+static READ32_HANDLER(DMA0_r)
+{
+ return DMA0ctrl;
+}
+
+static WRITE32_HANDLER(DMA0_w)
+{
+ if(((data^DMA0ctrl)&(1<<10)) && (data&(1<<10))) //DMAOn
+ {
+ UINT32 CTR=data;
+ UINT32 SRC=program_read_dword_32le(0x01800804);
+ UINT32 DST=program_read_dword_32le(0x01800808);
+ UINT32 CNT=program_read_dword_32le(0x0180080C);
+ int i;
+
+ if(CTR&0x2) //32 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT32 v=program_read_dword_32le(SRC+i*4);
+ program_write_dword_32le(DST+i*4,v);
+ }
+ }
+ else if(CTR&0x1) //16 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT16 v=program_read_word_32le(SRC+i*2);
+ program_write_word_32le(DST+i*2,v);
+ }
+ }
+ else //8 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT8 v=program_read_byte_32le(SRC+i);
+ program_write_byte_32le(DST+i,v);
+ }
+ }
+ data&=~(1<<10);
+ program_write_dword_32le(0x0180080C,0);
+ IntReq(7);
+ }
+ COMBINE_DATA(&DMA0ctrl);
+}
+
+static READ32_HANDLER(DMA1_r)
+{
+ return DMA1ctrl;
+}
+
+static WRITE32_HANDLER(DMA1_w)
+{
+ if(((data^DMA1ctrl)&(1<<10)) && (data&(1<<10))) //DMAOn
+ {
+ UINT32 CTR=data;
+ UINT32 SRC=program_read_dword_32le(0x01800814);
+ UINT32 DST=program_read_dword_32le(0x01800818);
+ UINT32 CNT=program_read_dword_32le(0x0180081C);
+ int i;
+
+ if(CTR&0x2) //32 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT32 v=program_read_dword_32le(SRC+i*4);
+ program_write_dword_32le(DST+i*4,v);
+ }
+ }
+ else if(CTR&0x1) //16 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT16 v=program_read_word_32le(SRC+i*2);
+ program_write_word_32le(DST+i*2,v);
+ }
+ }
+ else //8 bits
+ {
+ for(i=0;i<CNT;++i)
+ {
+ UINT8 v=program_read_byte_32le(SRC+i);
+ program_write_byte_32le(DST+i,v);
+ }
+ }
+ data&=~(1<<10);
+ program_write_dword_32le(0x0180081C,0);
+ IntReq(8);
+ }
+ COMBINE_DATA(&DMA1ctrl);
+}
+
+
+static ADDRESS_MAP_START( crystal_mem, ADDRESS_SPACE_PROGRAM, 32 )
+ 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_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size)
+
+ AM_RANGE(0x01801400, 0x01801403) AM_READ(Timer0_r) AM_WRITE(Timer0_w)
+ AM_RANGE(0x01801408, 0x0180140b) AM_READ(Timer1_r) AM_WRITE(Timer1_w)
+ AM_RANGE(0x01801410, 0x01801413) AM_READ(Timer2_r) AM_WRITE(Timer2_w)
+ AM_RANGE(0x01801418, 0x0180141b) AM_READ(Timer3_r) AM_WRITE(Timer3_w)
+ AM_RANGE(0x01802004, 0x01802007) AM_WRITE(PIO_w) AM_READ(PIO_r)
+
+ AM_RANGE(0x01800800, 0x01800803) AM_READ(DMA0_r) AM_WRITE(DMA0_w)
+ AM_RANGE(0x01800810, 0x01800813) AM_READ(DMA1_r) AM_WRITE(DMA1_w)
+
+ AM_RANGE(0x01800c04, 0x01800c07) AM_WRITE(IntAck_w)
+ AM_RANGE(0x01800000, 0x0180ffff) AM_RAM AM_BASE(&sysregs)
+ AM_RANGE(0x02000000, 0x027fffff) AM_RAM AM_BASE(&workram)
+
+ AM_RANGE(0x030000a4, 0x030000a7) AM_READ(FlipCount_r) AM_WRITE(FlipCount_w)
+
+ AM_RANGE(0x03000000, 0x0300ffff) AM_RAM AM_BASE(&vidregs)
+ AM_RANGE(0x03800000, 0x03ffffff) AM_RAM AM_BASE(&textureram)
+ AM_RANGE(0x04000000, 0x047fffff) AM_RAM AM_BASE(&frameram)
+ AM_RANGE(0x04800000, 0x04800fff) AM_READ(VR0_Snd_Read) AM_WRITE(VR0_Snd_Write)
+
+ AM_RANGE(0x05000000, 0x05000003) AM_READ(FlashCmd_r) AM_WRITE(FlashCmd_w)
+ AM_RANGE(0x05000000, 0x05ffffff) AM_READ(MRA32_BANK1)
+
+ AM_RANGE(0x44414F4C, 0x44414F7F) AM_RAM AM_BASE(&ResetPatch)
+
+ADDRESS_MAP_END
+
+static void PatchReset(void)
+{
+ //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
+*/
+
+#if 1
+ static const UINT32 Patch[] =
+ {
+ 0x40c0ea01,
+ 0xe906400a,
+ 0x40c02a20,
+ 0xe906400a,
+ 0xa1d03a20,
+ 0xdef4d4fa
+ };
+
+ memcpy(ResetPatch,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(ResetPatch,Patch,sizeof(Patch));
+#endif
+}
+
+static MACHINE_RESET(crystal)
+{
+ memset(sysregs,0,0x10000);
+ memset(vidregs,0,0x10000);
+ FlipCount=0;
+ IntHigh=0;
+ cpunum_set_irq_callback(0,icallback);
+ Bank=0;
+ memory_set_bankptr(1,memory_region(REGION_USER1)+0);
+ FlashCmd=0xff;
+ OldPort4=0;
+
+ DMA0ctrl=0;
+ DMA1ctrl=0;
+
+ Timer0ctrl=0;
+ Timer1ctrl=0;
+ Timer2ctrl=0;
+ Timer3ctrl=0;
+
+ Timer0=timer_alloc(Timer0cb);
+ timer_adjust(Timer0,attotime_never,0,attotime_never);
+
+ Timer1=timer_alloc(Timer1cb);
+ timer_adjust(Timer1,attotime_never,0,attotime_never);
+
+ Timer2=timer_alloc(Timer2cb);
+ timer_adjust(Timer2,attotime_never,0,attotime_never);
+
+ Timer3=timer_alloc(Timer3cb);
+ timer_adjust(Timer3,attotime_never,0,attotime_never);
+
+ VR0_Snd_Set_Areas(textureram,frameram);
+#ifdef IDLE_LOOP_SPEEDUP
+ FlipCntRead=0;
+#endif
+
+ PatchReset();
+}
+
+static VIDEO_START(crystal)
+{
+}
+
+static void plot_pixel_rgb(mame_bitmap *bitmap, int x, int y , int color)
+{
+ //565 to 555
+ color=(color&0x1f)|((color>>1)&0x7fe0);
+ if (bitmap->bpp == 32)
+ {
+ UINT32 cb=(color&0x1f)<<3;
+ UINT32 cg=(color&0x3e0)>>2;
+ UINT32 cr=(color&0x7c00)>>7;
+ *BITMAP_ADDR32(bitmap, y, x) = cb | (cg<<8) | (cr<<16);
+ }
+ else
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = color;
+ }
+}
+
+static UINT16 GetVidReg(UINT16 reg)
+{
+ return program_read_word_32le(0x03000000+reg);
+}
+
+static void SetVidReg(UINT16 reg,UINT16 val)
+{
+ program_write_word_32le(0x03000000+reg,val);
+}
+
+
+static VIDEO_UPDATE(crystal)
+{
+ int DoFlip;
+
+
+ UINT32 B0=0x0;
+ UINT32 B1=(GetVidReg(0x90)&0x8000)?0x400000:0x100000;
+ UINT16 *Front,*Back;
+ UINT16 *Visible,*DrawDest;
+ UINT16 *srcline;
+ int x,y;
+ UINT16 head,tail;
+
+ if(GetVidReg(0x8e)&1)
+ {
+ Front=(UINT16*) (frameram+B1/4);
+ Back=(UINT16*) (frameram+B0/4);
+ }
+ else
+ {
+ Front=(UINT16*) (frameram+B0/4);
+ Back=(UINT16*) (frameram+B1/4);
+ }
+
+ Visible=(UINT16*) Front;
+ DrawDest=(UINT16 *) frameram;
+
+
+ if(GetVidReg(0x8c)&0x80)
+ DrawDest=Front;
+ else
+ DrawDest=Back;
+
+// DrawDest=Visible;
+
+ srcline=(UINT16 *) DrawDest;
+
+ DoFlip=0;
+ head=GetVidReg(0x82);
+ tail=GetVidReg(0x80);
+ while((head&0x7ff)!=(tail&0x7ff))
+ {
+ DoFlip=ProcessPacket(0x03800000+head*64,DrawDest,(UINT8*)textureram);
+ head++;
+ head&=0x7ff;
+ if(DoFlip)
+ break;
+ }
+
+ if(DoFlip)
+ SetVidReg(0x8e,GetVidReg(0x8e)^1);
+
+ srcline=(UINT16 *) Visible;
+ for(y=0;y<240;y++)
+ for(x=0;x<320;x++)
+ plot_pixel_rgb(bitmap,x,y,srcline[y*512+x]);
+ return 0;
+}
+
+static VIDEO_EOF(crystal)
+{
+ UINT16 head,tail;
+ int DoFlip=0;
+
+ head=GetVidReg(0x82);
+ tail=GetVidReg(0x80);
+ while((head&0x7ff)!=(tail&0x7ff))
+ {
+ UINT16 Packet0=program_read_word_32le(0x03800000+head*64);
+ if(Packet0&0x81)
+ DoFlip=1;
+ head++;
+ head&=0x7ff;
+ if(DoFlip)
+ break;
+ }
+ SetVidReg(0x82,head);
+ if(DoFlip)
+ {
+ if(FlipCount)
+ FlipCount--;
+
+ }
+}
+
+static INTERRUPT_GEN(crystal_interrupt)
+{
+ IntReq(24); //VRender0 VBlank
+}
+
+static INPUT_PORTS_START(crystal)
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(3)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(4)
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4)
+
+ PORT_START
+ 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_BIT(0x80, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME(DEF_STR( Test )) PORT_CODE(KEYCODE_F2)
+
+ PORT_START
+ 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 struct VR0Interface vr0_interface =
+{
+ 0x04800000
+};
+
+
+static MACHINE_DRIVER_START( crystal )
+ MDRV_CPU_ADD(SE3208, 43000000)
+ MDRV_CPU_PROGRAM_MAP(crystal_mem,0)
+ MDRV_CPU_VBLANK_INT(crystal_interrupt,1)
+
+ MDRV_SCREEN_REFRESH_RATE(60)
+ MDRV_SCREEN_VBLANK_TIME(DEFAULT_60HZ_VBLANK_DURATION)
+
+ MDRV_MACHINE_RESET(crystal)
+
+ MDRV_NVRAM_HANDLER(generic_0fill)
+
+ MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER )
+ MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB15)
+ MDRV_SCREEN_SIZE(320, 240)
+ MDRV_SCREEN_VISIBLE_AREA(0, 319, 0, 239)
+ MDRV_PALETTE_LENGTH(8192)
+
+ MDRV_VIDEO_START(crystal)
+ MDRV_VIDEO_UPDATE(crystal)
+ MDRV_VIDEO_EOF(crystal)
+
+ MDRV_SPEAKER_STANDARD_STEREO("left", "right")
+
+ MDRV_SOUND_ADD(VRENDER0, 0)
+ MDRV_SOUND_CONFIG(vr0_interface)
+ MDRV_SOUND_ROUTE(0, "left", 1.0)
+ MDRV_SOUND_ROUTE(1, "right", 1.0)
+MACHINE_DRIVER_END
+
+ROM_START( crysbios )
+ ROM_REGION( 0x20000, REGION_CPU1, 0 ) // bios
+ ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb) )
+
+ ROM_REGION32_LE( 0x3000000, REGION_USER1, ROMREGION_ERASEFF ) // Flash
+
+ ROM_REGION( 0x10000, REGION_USER2, ROMREGION_ERASEFF ) //Unmapped flash
+ROM_END
+
+ROM_START( crysking )
+ ROM_REGION( 0x20000, REGION_CPU1, 0 ) // bios
+ ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb))
+
+ ROM_REGION32_LE( 0x3000000, REGION_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, REGION_USER2, ROMREGION_ERASEFF ) //Unmapped flash
+ROM_END
+
+ROM_START( evosocc )
+ ROM_REGION( 0x20000, REGION_CPU1, 0 ) // bios
+ ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(BEFF39A9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb))
+
+ ROM_REGION32_LE( 0x3000000, REGION_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, REGION_USER2, ROMREGION_ERASEFF ) //Unmapped flash
+ROM_END
+
+
+static DRIVER_INIT(crysking)
+{
+ UINT16 *Rom=(UINT16*) memory_region(REGION_USER1);
+
+ //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*) memory_region(REGION_USER1);
+ 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
+}
+
+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 )