/*Barquest MPU4 Video hardware (The original Crystal Maze SWP, for all you Brits)

Driver converted to video only test driver by DOX
Since updated from information found by El Condor, iamtheone and DialTone (who also provided new code routines).

You know, a great way to please the project coordinator is to get this damn thing working!

NOTE: Without someone with a better understanding of the VDC used in this hardware, this driver will never work.
There, I said it (EC).

I'd like to inform anyone working on this that most of this is documented, and many games on this hardware are pure skill.

The 68k board hooks up to a Barcrest MPU4 unit, which is also unemulated.
The link is a serial link, about 500MHz or faster (is it necessary?).

The VIDEO.P1 ROM in the audited sets is loaded onto the MPU4 board, and sets it to receive data through the link rather than
through its normal ROM board.

Experts with this hardware (you know who you are), are invited to assist.

DialTone has one of the newer revision boards with the extra RAM, which is useful.

What's more useful is that MFME have picked up the proverbial ball and run with it to make a closed source emulation
of the hardware (which has a debugger of sorts, so maybe someone can use that for comparison?).

Very preliminary memory map and info (some of this may be wrong)

ROM loading order is known.

I can't see any gfx patterns inside . compressed ? encrypted ? strange format ? (DOX)

The gfx seem to be decompressed by the program while it runs, it then populates the pattern RAM with the necessary tiles.

Next, a SCN2674 CRT controller processes this, setting a register per 32 byte character.

0 is top left ((0,0) in pixels), which points to the first 32 bytes of character RAM. This progresses until the whole 
screen has been drawn, at which point, it resets to 0.

It appears that this drawing does not take place directly, rather the SCN2674 transfers this to a data RAM stack. This
is then acted on by an EF9369 palette controller, which converts the original 16 colour codes into another colour set,
chosen from an internal 4096 colour palette.

It also appears that the rows are built in RAM, and then transferred to the screen as one unit - more complex than I'll
ever be able to cope with.

However, I can ask an engineer (iamtheone) who cowrote this game: here's what he says:

"The graphics in the ROM are compressed. We uncompressed them as and when required. A compressed 8x8 character would be
stored as 8 pointers which pointed to a 32bit chunk of pixels. So an empty character would have 8 pointers which all 
pointed to the same 32bit chunk of pixels. 

0 --------> 32bit chunk of 8 pixels (4bpp) 
1 
2 
3 
4 
5 
6 
7 

So from the above, if we had a 4 x 2 block of characters that we wanted to map on the screen. It would look like this.

HELLO_C 4 2 $F000 $F000 $F000 $F000 $F000 $F000 $F000 $F000 

HELLO_C is the name of the character block to map 
4 2 is the x and y size of the characters 

The rest of the data is $F for the colour attribute mask (Generally $F, but in Crystal Maze any value from $0 to $F,
depending on the palette wanted) and the 12bit 000 is the offset into the graphics memory 0 = $C00000 

The 0 offset will point to $C00000 which contains the uncompressed block as mentioned above 

0 --------> 32bit chunk of 8 pixels (4bpp) 
1 
2 
3 
4 
5 
6 
7 

And to confuse you even more, we could uncompress the graphics anywhere in the 128k graphics ram. So the offset of 0
which is stored in the character blocks to map. This could have a value added to it, to point in to the correct area.
So if we uncompressed the block to $C00020 then the 0 will have a 1 added to it, so that if can still be stored in the 
ROM as a list of offsets but it is relocatable. 

So to sum up, the graphics are compressed as pixels and 8 pointers to make up each character block. 

These get uncompressed in memory eg $C00000, there may be lots of them. Then the characters offset are just put on the 
screen. 

It sounds really confusing, but it's pretty much like a C64 used to do it (worth checking MESS or similar?). 

The current driver just uses generic handling for everything bar the displayed screen.

Details (datasheets, etc) can be found by searching the MFME forums (http://www.mfme.co.uk), or by PM'ing ElCondor on forums like www.fruitforums.com
or even www.mameworld.info
*/
#include "driver.h"
#include "machine/random.h"
#include "machine/6840ptm.h"
#include "vidhrdw/generic.h"
#include "cpu/m68000/m68000.h"
//#include "sound/ay8910.h" MPU4 onboard sound
#include "sound/saa1099.h" //Video Card sound

VIDEO_START(mpu4test)
{
	return 0;
}

VIDEO_UPDATE(mpu4test)
{
//I doubt any of this is correct, and it causes problems, so out it goes.
#if 0
	if(code_pressed_memory(KEYCODE_Q)) //press q to save vram to disk. Using GameGear format, the debug font can be seen
	{
		FILE *p=fopen("ram.bin","wb");
		fwrite(&videoram[0],1,0x20000,p);
		fclose(p);	
	}
	#endif
	{
		int x,y;//63 columns by 37 rows gives 504x296 not 256x256
		int col, row; // convert tp col and row
		int cx, cy;	// x and y within char
		int bytcnt;

		// 63 x 37 chars each of 32 bytes
		for (int ramloc = 0; ramloc < 74592; ramloc++) {
			row = (ramloc / 2016);			// range of 0 thru 36 [37 rows]
			col = ((ramloc % 2016) / 32);	// range of 0 thru 62 [63 cols]
			bytcnt = (ramloc % 32);			// range 0 thru 31 (32 bytes per char)
			cy = (bytcnt / 4);				// range of 0 thru 7 (8 lines per char)
			cx = (bytcnt % 4) * 2;			// range of 0, 2, 4, 6 (start of each cell)
			
			x = (col * 8) + cx;
			y = (row * 8) + cy;
						
			plot_pixel(bitmap, x, y, (videoram[ramloc] & 0xf0) >> 4 );
			plot_pixel(bitmap, (x + 1), y, (videoram[ramloc] & 0x0f) );
		}
	}
#endif

	if(code_pressed_memory(KEYCODE_W)) //press w-i to generate interrupt
		cpunum_set_input_line(0, 1, HOLD_LINE);

	if(code_pressed_memory(KEYCODE_E))
		cpunum_set_input_line(0, 2, HOLD_LINE);

	if(code_pressed_memory(KEYCODE_R))
		cpunum_set_input_line(0, 3, HOLD_LINE);

	// Just a note that IRQs 4 thru 7 ought not to do anything meaningful!!
	// They don't, just seem to give the system enough of a headache to miss a screen update or two.
	if(code_pressed_memory(KEYCODE_T))
		cpunum_set_input_line(0, 4, HOLD_LINE);

	if(code_pressed_memory(KEYCODE_Y))
		cpunum_set_input_line(0, 5, HOLD_LINE);

	if(code_pressed_memory(KEYCODE_U))
		cpunum_set_input_line(0, 6, HOLD_LINE);

	if(code_pressed_memory(KEYCODE_I))
		cpunum_set_input_line(0, 7, HOLD_LINE);

}

// INTERRUPT HANDLER FOR THE 68K (VIDEO)
static void cpu0_ptm_irq(int state)
{
  cpunum_set_input_line(0, MC68000_IRQ_1, PULSE_LINE);
}

// 6840 PTM handler

static struct ptm6840_interface ptm_vid_intf =
{
  NULL, NULL, NULL,
  cpu0_ptm_irq
};

static READ16_HANDLER( vdc_r )
{
  if (offset & 0x02)
  	return 0x3f;
  else
  	return 0;
}

static ADDRESS_MAP_START( mpu4test_map, ADDRESS_SPACE_PROGRAM, 16 )
	AM_RANGE(0x000000, 0x0fffff) AM_ROM	                // Program / GFX ROM - DT
	AM_RANGE(0x800000, 0x80ffff) AM_RAM	                // 64K RAM - Stack and Char Pattern RAM - DT
// ?? interrupt control ? video control ? (I can't make my mind up as to whether this is the register
// for the 2674 or not - EC
//  AM_RANGE(0x900000, 0x900003) AM_WRITE(MWA16_RAM)       Most likely candidate is the 6850 ACIA - DT
// This exact same unit is present 'inside' the MPU4 Program module, and now has a codebase in the machine folder - EC
// AM_RANGE(0xa00000, 0xa0000f) AM_RAM                  // Hazard a guess that this is the EF9369? - DT
// I'll run with that, 16 values, 16 colours at any one time - EC
	AM_RANGE(0xb00000, 0xb0000f) AM_READ(ptm6840_0_r16) // MC6840 PTM - DT
	AM_RANGE(0xb00000, 0xb0000f) AM_WRITE(ptm6840_0_w16)// Will this do more when the game runs, I doubt it's without any purpose at all.
	AM_RANGE(0xc00000, 0xc1ffff) AM_WRITE(MWA16_RAM)    //AM_BASE(&videoram) This is the character Address RAM for the SCN2674
	AM_RANGE(0xff8000, 0xff800f) AM_READ(vdc_r)	        // Possibly the SCN2674 VDC perhaps? - DT, seem to poll 00/02 ~20000 times which would be regs 0 and 1 - irq and status
//	AM_RANGE(0xff8000, 0xff800f) AM_RAM                 // Possibly the SCN2674 VDC perhaps? - DT, seem to poll 00/02 ~20000 times which would be regs 0 and 1 - irq and status
//	AM_RANGE(0xff9000, 0xff900f) AM_RAM                 // Candidate for SCN, but illegal commands being sent if so - DT. Row Buffer? - EC
//	AM_RANGE(0xffd000, 0xffd011) AM_RAM                 // protection ? write/read/compare.. like mpu4 characteriser , code near $6216 , no security chip actually on this board, so may be fed by other unit

ADDRESS_MAP_END

INPUT_PORTS_START( mpu4test )
INPUT_PORTS_END

static struct GfxLayout charlayout =
{
	8, 8, //Known - width , height of tile
	RGN_FRAC(1,4),
	4,
	{ 0,1,2,3 },
	{ 0, 4, 8, 12, 16, 20, 24, 28},
	{ 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },//Unknown
	32*8//Known
};

static struct GfxDecodeInfo gfxdecodeinfo[] =//No real need for this, works more like X the Ball
{
	//{ REGION_CPU1, 0x100000, &charlayout,	0, 16 },
	{ 0, 0x100000, &charlayout,	0, 16 },
	{ -1 }
};

static MACHINE_INIT( mpu4vid )
{
  // setup ptm ///////////////////////////////////////////////////
  ptm6840_unconfig();
  ptm6840_config(0, &ptm_vid_intf );

  // reset the board /////////////////////////////////////////////
  // on_reset();
}

static MACHINE_DRIVER_START( mpu4vid )           // A full driver would also use an MPU4 board (from mpu4.c), but this is essentially a proof of concept.
  	MDRV_MACHINE_INIT(init)                    // main mpu4 board initialisation
	MDRV_CPU_ADD(M68000, 10000000)             // According to manual
	MDRV_CPU_PROGRAM_MAP(mpu4test_map,0)
	MDRV_FRAMES_PER_SECOND(60)
	MDRV_VBLANK_DURATION(DEFAULT_60HZ_VBLANK_DURATION)

	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_SCREEN_SIZE(504, 304)                 //Extra 8 rows needed for UI overhang
	MDRV_VISIBLE_AREA(0*8, 63*8-1, 1*8, 38*8-1)//Gives the correct resolution, 504x296
	MDRV_GFXDECODE(gfxdecodeinfo)
	MDRV_PALETTE_LENGTH(16)                    // Palette entries available to the SCN2674
	MDRV_COLORTABLE_LENGTH(4096)               // Palette -> Colour mappings handled by the EF9369
	MDRV_VIDEO_START(mpu4test)
	MDRV_VIDEO_UPDATE(mpu4test)

	MDRV_SPEAKER_STANDARD_STEREO("left", "right")
	MDRV_SOUND_ADD(SAA1099, 0)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "left", 1.0)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "right", 1.0)
MACHINE_DRIVER_END

ROM_START( cmzeswp3 )
	ROM_REGION( 0x500000, REGION_CPU1, 0 ) /* 68000 Code and gfx data. Why is cheap hardware always so complex?*/
	ROM_LOAD16_BYTE( "cm3.p1",  0x000000, 0x80000,  CRC(2d2edee5) )
	ROM_LOAD16_BYTE( "cm3.p2",  0x000001, 0x80000,  CRC(c223d7b9) )

	ROM_LOAD16_BYTE( "cm3.p3",  0x100000, 0x80000,  CRC(2959c77b) ) //The set is mentioned in the Troutman DAT file for FME ROMs
	ROM_LOAD16_BYTE( "cm3.p4",  0x100001, 0x80000,  CRC(b7873e9a) ) //This file may have a few minor errors, so it's possible this dump is bad.

	ROM_LOAD16_BYTE( "cm3.p5",  0x200000, 0x80000,  CRC(c8375070) ) //To run MFME rom set, change the name cm3.pa to cm3.p10
	ROM_LOAD16_BYTE( "cm3.p6",  0x200001, 0x80000,  CRC(1ea36938) )

	ROM_LOAD16_BYTE( "cm3.p7",  0x300000, 0x80000,  CRC(9de3802e) )
	ROM_LOAD16_BYTE( "cm3.p8",  0x300001, 0x80000,  CRC(1e6e60b0) )

	ROM_LOAD16_BYTE( "cm3.p9",   0x400000, 0x80000,  CRC(bfba55a7) )
	ROM_LOAD16_BYTE( "cm3.p10",  0x400001, 0x80000,  CRC(07edda81) )

  //Right, just to make this easier, I will now lay out a few other ROMsets we have for this game:
  //Just mix and match as necessary - a pair of ROMCMP reports is also present in the driver folder,

#if 0;
  //Version 1's ROMS, no point in cluttering the driver until we have something working
  //The program is almost entirely different, supports 4 LED displays (2 Players) only.
  //Non-payout, actually a merging of the Version 1 game with the Version 3 high score support

	ROM_LOAD16_BYTE( "am1z.p1",  0x000000, 0x80000,  CRC(d2fdda6d) )
	ROM_LOAD16_BYTE( "am1z.p2",  0x000001, 0x80000,  CRC(1637170f) )

	ROM_LOAD16_BYTE( "am1g.p1",  0x100000, 0x80000,  CRC(e8cf8203) )
	ROM_LOAD16_BYTE( "am1g.p2",  0x100001, 0x80000,  CRC(7b036151) )

	ROM_LOAD16_BYTE( "am1g.p3",  0x200000, 0x80000,  CRC(48f17b20) )
	ROM_LOAD16_BYTE( "am1g.p4",  0x200001, 0x80000,  CRC(2b3d9a97) )

	ROM_LOAD16_BYTE( "am1g.p5",  0x300000, 0x80000,  CRC(68286bb1) )
	ROM_LOAD16_BYTE( "am1g.p6",  0x300001, 0x80000,  CRC(a6b498ad) )

	ROM_LOAD16_BYTE( "am1g.p7",  0x400000, 0x80000,  CRC(15882699) )
	ROM_LOAD16_BYTE( "am1g.p8",  0x400001, 0x80000,  CRC(6f0f855b) )

  //Version 2 (With Ocean Zone!) This is also non-payout. At least this one works properly.

	ROM_LOAD16_BYTE( "am2z.p1",  0x000000, 0x80000,  CRC(f27e02f0) )
	ROM_LOAD16_BYTE( "am2z.p2",  0x000001, 0x80000,  CRC(4d24f482) )

	ROM_LOAD16_BYTE( "am2g.p1",  0x100000, 0x80000,  CRC(115402db) )
	ROM_LOAD16_BYTE( "am2g.p2",  0x100001, 0x80000,  CRC(5d804fbb) )

	ROM_LOAD16_BYTE( "am2g.p3",  0x200000, 0x80000,  CRC(5ead0c06) )
	ROM_LOAD16_BYTE( "am2g.p4",  0x200001, 0x80000,  CRC(de4fb542) )

	ROM_LOAD16_BYTE( "am2g.p5",  0x300000, 0x80000,  CRC(80b01ce2) )
	ROM_LOAD16_BYTE( "am2g.p6",  0x300001, 0x80000,  CRC(3e134ecc) )

	ROM_LOAD16_BYTE( "am2g.p7",  0x400000, 0x80000,  CRC(6eb36f1d) )
	ROM_LOAD16_BYTE( "am2g.p8",  0x400001, 0x80000,  CRC(dda353ef) )

  //Another Team Challenge (Version 3) apparently,
  //Produced by Townsend, Foster and Eaton to make an Amusement Only set for areas where SWPs are illegal
  //(Like the Isle of Man, and such?)
  //Testing this on other emulators produces a crash, given the program is only an early revision, it may never have worked,
  //It was reportedly on the Barcrest BBS for a while, during location test?

	ROM_LOAD16_BYTE( "am3z.p1",  0x000000, 0x80000,  CRC(9484e656) )
	ROM_LOAD16_BYTE( "am3z.p2",  0x000001, 0x80000,  CRC(1865ee80) )

	ROM_LOAD16_BYTE( "am3g.p1",  0x100000, 0x80000,  CRC(49fe36af) )
	ROM_LOAD16_BYTE( "am3g.p2",  0x100001, 0x80000,  CRC(b8823cbd) )

	ROM_LOAD16_BYTE( "am3g.p3",  0x200000, 0x80000,  CRC(b1870f17) )
	ROM_LOAD16_BYTE( "am3g.p4",  0x200001, 0x80000,  CRC(c015d446) )

	ROM_LOAD16_BYTE( "am3g.p5",  0x300000, 0x80000,  CRC(9de2802e) )
	ROM_LOAD16_BYTE( "am3g.p6",  0x300001, 0x80000,  CRC(1e6e60b0) )

	ROM_LOAD16_BYTE( "am3g.p7",  0x400000, 0x80000,  CRC(a4611e29) )
	ROM_LOAD16_BYTE( "am3g.p8",  0x400001, 0x80000,  CRC(1a10c22e) )

ROM_END

//GAMEX( 1994, cmzeswp3, 0, mpu4test, mpu4test, 0, ROT0, "Barcrest", "The Crystal Maze: Team Challenge (SWP) v0.9", GAME_NO_SOUND | GAME_NOT_WORKING )
