Author Topic: Care to follow along?  (Read 11837 times)

Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Care to follow along?
« on: May 12, 2014, 08:40:59 PM »
So I'm going to port this driver bit by bit:

http://git.redump.net/mame/plain/src/mame/drivers/gotya.c

You can follow along in this thread :)


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #1 on: May 12, 2014, 09:03:39 PM »
Let's start with the cpu map


Code: [Select]
static ADDRESS_MAP_START( gotya_map, AS_PROGRAM, 8, gotya_state )
AM_RANGE(0x0000, 0x3fff) AM_ROM
AM_RANGE(0x5000, 0x5fff) AM_RAM
AM_RANGE(0x6000, 0x6000) AM_READ_PORT("P1")
AM_RANGE(0x6001, 0x6001) AM_READ_PORT("P2")
AM_RANGE(0x6002, 0x6002) AM_READ_PORT("DSW")
AM_RANGE(0x6004, 0x6004) AM_WRITE(gotya_video_control_w)
AM_RANGE(0x6005, 0x6005) AM_WRITE(gotya_soundlatch_w)
AM_RANGE(0x6006, 0x6006) AM_WRITEONLY AM_SHARE("scroll")
AM_RANGE(0x6007, 0x6007) AM_WRITE(watchdog_reset_w)
AM_RANGE(0xc000, 0xc7ff) AM_RAM_WRITE(gotya_videoram_w) AM_SHARE("videoram")
AM_RANGE(0xc800, 0xcfff) AM_RAM_WRITE(gotya_colorram_w) AM_SHARE("colorram")
AM_RANGE(0xd000, 0xd3df) AM_RAM AM_SHARE("videoram2")
AM_RANGE(0xd3e0, 0xd3ff) AM_RAM AM_SHARE("spriteram")
ADDRESS_MAP_END

MCFG_CPU_ADD("maincpu", Z80,18432000/6) /* 3.072 MHz ??? */
MCFG_CPU_PROGRAM_MAP(gotya_map)

With these two pieces of information, you can see that the main cpu of this game is a z80.

for fba, this translates to:

Code: [Select]
ZetInit(0); // initialize the first z80
ZetOpen(0);
ZetMapMemory(DrvZ80ROM, 0x0000, 0x3fff, ZET_ROM); // AM_RANGE(0x0000, 0x3fff) AM_ROM
ZetMapMemory(DrvZ80RAM, 0x5000, 0x5fff, ZET_RAM); // AM_RANGE(0x5000, 0x5fff) AM_RAM
ZetMapMemory(DrvVidRAM, 0xc000, 0xc7ff, ZET_RAM); // AM_RANGE(0xc000, 0xc7ff) AM_RAM_WRITE(gotya_videoram_w) AM_SHARE("videoram")
ZetMapMemory(DrvColRAM, 0xc800, 0xcfff, ZET_RAM); // AM_RANGE(0xc800, 0xcfff) AM_RAM_WRITE(gotya_colorram_w) AM_SHARE("colorram")
ZetMapMemory(DrvVidRAM2, 0xd000, 0xd3ff, ZET_RAM); // AM_RANGE(0xd000, 0xd3df) AM_RAM AM_SHARE("videoram2")
// this is tricky, fba does pages of 256 bytes, the spriteram is only 32 (0x20) at the end of video ram, since
// we can only do 0x100 pages, just use a pointer to sprite ram
DrvSprRAM = DrvVidRAM2 + 0x3e0;
ZetSetWriteHandler(gotya_write); // use a handler to handle anything that isn't rom or ram
ZetSetReadHandler(gotya_read); // ""
ZetClose();

static void __fastcall gotya_write(UINT16 address, UINT8 data)
{
switch (address)
{
case 0x6004: // AM_RANGE(0x6004, 0x6004) AM_WRITE(gotya_video_control_w)
scroll = (scroll & 0xff) | ((data & 0x01) << 8); // mame handles this as "bit 8", just skip ahead
flipscreen = data & 0x02;
return;

case 0x6005: // AM_RANGE(0x6005, 0x6005) AM_WRITE(gotya_soundlatch_w)
gotya_soundlatch(data); // handle this later
return;

case 0x6006: // AM_RANGE(0x6006, 0x6006) AM_WRITEONLY AM_SHARE("scroll")
scroll = (scroll & 0x100) | data;
return;

case 0x6007: // AM_RANGE(0x6007, 0x6007) AM_WRITE(watchdog_reset_w)
watchdog = 0;
return;
}
}

static UINT8 __fastcall gotya_read(UINT16 address)
{
switch (address)
{
case 0x6000: // AM_RANGE(0x6000, 0x6000) AM_READ_PORT("P1")
return DrvInputs[0]; // assemble later on...

// this dip/ input assembly is abit advanced now, but will be explained a bit later, just trust with me on this...
case 0x6001: // AM_RANGE(0x6001, 0x6001) AM_READ_PORT("P2")
return (DrvDips[0] & 0x10) | (DrvInputs[1] & 0xef); // assemble later on...

case 0x6002: // AM_RANGE(0x6002, 0x6002) AM_READ_PORT("DSW")
return (DrvDips[1] & 0xf2) | (DrvInputs[2] & 0x0b);
}

return 0;
}
« Last Edit: May 12, 2014, 11:57:13 PM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #2 on: May 12, 2014, 09:21:09 PM »
Next, we'll do some basic setup for Init, Reset, and exit.
I really just copy and paste a lot of this from other drivers (I like 4enraya lol)

This line allows us to set up our sound hardware
   MCFG_SAMPLES_ADD("samples", gotya_samples_interface)
   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)

This gets me to this point:

Code: [Select]

static void __fastcall gotya_write(UINT16 address, UINT8 data)
{
switch (address)
{
case 0x6004: // AM_RANGE(0x6004, 0x6004) AM_WRITE(gotya_video_control_w)
scroll = (scroll & 0xff) | ((data & 0x01) << 8); // mame handles this as "bit 8", just skip ahead
flipscreen = data & 0x02;
return;

case 0x6005: // AM_RANGE(0x6005, 0x6005) AM_WRITE(gotya_soundlatch_w)
gotya_soundlatch(data); // handle this later
return;

case 0x6006: // AM_RANGE(0x6006, 0x6006) AM_WRITEONLY AM_SHARE("scroll")
scroll = (scroll & 0x100) | data;
return;

case 0x6007: // AM_RANGE(0x6007, 0x6007) AM_WRITE(watchdog_reset_w)
watchdog = 0;
return;
}
}

static UINT8 __fastcall gotya_read(UINT16 address)
{
switch (address)
{
case 0x6000: // AM_RANGE(0x6000, 0x6000) AM_READ_PORT("P1")
return DrvInputs[0]; // assemble later on...

// this dip/ input assembly is abit advanced now, but will be explained a bit later, just trust with me on this...
case 0x6001: // AM_RANGE(0x6001, 0x6001) AM_READ_PORT("P2")
return (DrvDips[0] & 0x10) | (DrvInputs[1] & 0xef); // assemble later on...

case 0x6002: // AM_RANGE(0x6002, 0x6002) AM_READ_PORT("DSW")
return (DrvDips[1] & 0xf2) | (DrvInputs[2] & 0x0b);
}

return 0;
}

static INT32 DrvDoReset()
{
memset (AllRam, 0, RamEnd - AllRam); // reset all our ram

ZetOpen(0); // open our z80
ZetReset(); // reset it
ZetClose(); // close it back up

BurnSampleReset();

// set these all to 0 otherwise the game will freak out
scroll = 0;
watchdog = 0;
flipscreen = 0;

return 0;
}


// put some stuff here later...


static INT32 DrvInit()
{
AllMem = NULL;
MemIndex();
INT32 nLen = MemEnd - (UINT8 *)0;
if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
memset(AllMem, 0, nLen);
MemIndex();

{
// load roms here
// decode tiles here
}

ZetInit(0); // initialize the first z80
ZetOpen(0);
ZetMapMemory(DrvZ80ROM, 0x0000, 0x3fff, ZET_ROM); // AM_RANGE(0x0000, 0x3fff) AM_ROM
ZetMapMemory(DrvZ80RAM, 0x5000, 0x5fff, ZET_RAM); // AM_RANGE(0x5000, 0x5fff) AM_RAM
ZetMapMemory(DrvVidRAM, 0xc000, 0xc7ff, ZET_RAM); // AM_RANGE(0xc000, 0xc7ff) AM_RAM_WRITE(gotya_videoram_w) AM_SHARE("videoram")
ZetMapMemory(DrvColRAM, 0xc800, 0xcfff, ZET_RAM); // AM_RANGE(0xc800, 0xcfff) AM_RAM_WRITE(gotya_colorram_w) AM_SHARE("colorram")
ZetMapMemory(DrvVidRAM2, 0xd000, 0xd3ff, ZET_RAM); // AM_RANGE(0xd000, 0xd3df) AM_RAM AM_SHARE("videoram2")
// this is tricky, fba does pages of 256 bytes, the spriteram is only 32 (0x20) at the end of video ram, since
// we can only do 0x100 pages, just use a pointer to sprite ram
DrvSprRAM = DrvVidRAM2 + 0x3e0;
ZetSetWriteHandler(gotya_write); // use a handler to handle anything that isn't rom or ram
ZetSetReadHandler(gotya_read); // ""
ZetClose();

BurnSampleInit(0); // start our sound hardware
BurnSampleSetAllRoutesAllSamples(1.00, BURN_SND_ROUTE_BOTH); // set our volume levels for channels

GenericTilesInit(); // always, this starts the tile drawing routines

DrvDoReset(); // always start with resetting the machine

return 0;
}

static INT32 DrvExit()
{
GenericTilesExit(); // always, this exits the tile drawing routines

ZetExit(); // exit the z80
BurnSampleExit(); // exit our sound hardware

BurnFree(AllMem); // free all ram

return 0;
}
« Last Edit: May 12, 2014, 11:57:30 PM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #3 on: May 12, 2014, 09:34:35 PM »
Now let's do some more fba-specific stuff. We need to set up our "memindex", really we're just allocating a blob of ram and setting pointers to offsets inside of it. This just makes it easier to track how much ram we're allocating.

Here's a snippet

Code: [Select]

static INT32 MemIndex()
{
UINT8 *Next; Next = AllMem;

DrvZ80ROM = Next; Next += 0x004000; // size from ZetMapMemory(DrvZ80ROM, 0x0000, 0x3fff

// gfx0 size from ROM_REGION( 0x1000,  "gfx1", 0 )
// also take this GFXDECODE_ENTRY( "gfx1", 0, charlayout,   0, 16 )
// which leads us to this in charlayout 2,      /* 2 bits per pixel *
// logically you can do (0x1000 * 8) / 2
// this is (tile_length * 8 [bits per byte]) / 2 (bits per pixel)
DrvGfxROM0 = Next; Next += 0x004000;
// gfx1 size is the same ROM_REGION( 0x1000,  "gfx2", 0 )
DrvGfxROM1 = Next; Next += 0x004000;

DrvColPROM = Next; Next += 0x000120; // ROM_REGION( 0x0120,  "proms", 0 )

// palette size can be tricky, but in this instance, it is pretty straight-forward
// MCFG_PALETTE_ADD("palette", 16*4). always make it size of UINT32 (4 bytes, this allows 24-bit colors)
DrvPalette = (UINT32*)Next; Next += 0x0040 * sizeof(UINT32);

AllRam = Next; // start of ram, use this weith ramend to allow us to clear/save every bit of ram

DrvZ80RAM = Next; Next += 0x001000; // size from ZetMapMemory(DrvZ80RAM, 0x5000, 0x5fff
DrvVidRAM = Next; Next += 0x000800; // size from ZetMapMemory(DrvVidRAM, 0xc000, 0xc7ff
DrvColRAM = Next; Next += 0x000800; // size from ZetMapMemory(DrvColRAM, 0xc800, 0xcfff
DrvVidRAM2 = Next; Next += 0x000400; // size from ZetMapMemory(DrvVidRAM2, 0xd000, 0xd3ff

RamEnd = Next;

MemEnd = Next;

return 0;
}

static INT32 DrvInit()
{
AllMem = NULL;
MemIndex();
INT32 nLen = MemEnd - (UINT8 *)0;
if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
memset(AllMem, 0, nLen);
« Last Edit: May 13, 2014, 12:01:21 AM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #4 on: May 12, 2014, 09:40:34 PM »
Now let's add our rom loading.

Code: [Select]

static INT32 DrvInit()
{
AllMem = NULL;
MemIndex();
INT32 nLen = MemEnd - (UINT8 *)0;
if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
memset(AllMem, 0, nLen);
MemIndex();

{
if (BurnLoadRom(DrvZ80ROM + 0x0000,   0, 1)) return 1;
// ROM_LOAD( "gb-06.bin",  0x0000, 0x1000, CRC(7793985a) SHA1(23aa8bd161e700bea59b92075423cdf55e9a26c3) )

if (BurnLoadRom(DrvZ80ROM + 0x1000,   1, 1)) return 1;
// ROM_LOAD( "gb-05.bin",  0x1000, 0x1000, CRC(683d188b) SHA1(5341c62f5cf384c73be0d7a0a230bb8cebfbe709) )

if (BurnLoadRom(DrvZ80ROM + 0x2000,   2, 1)) return 1;
// ROM_LOAD( "gb-04.bin",  0x2000, 0x1000, CRC(15b72f09) SHA1(bd941722ed1310d5c8ca8a44899368cba3815f3b) )

if (BurnLoadRom(DrvZ80ROM + 0x3000,  3, 1)) return 1;
// ROM_LOAD( "gb-03.bin",  0x3000, 0x1000, CRC(f34d90ab) SHA1(bec5f6a34a273f308083a280f2b425d9c273c69b) )    /* this is the only ROM that passes the ROM test */

// ROM_REGION( 0x1000,  "gfx1", 0 )    /* characters */
if (BurnLoadRom(DrvGfxROM0 + 0x0000,  4, 1)) return 1;
// ROM_LOAD( "gb-12.bin",  0x0000, 0x1000, CRC(4993d735) SHA1(9e47876238a8af3659721191a5f75c33507ed1a5) )

// ROM_REGION( 0x1000,  "gfx2", 0 )    /* sprites */
if (BurnLoadRom(DrvGfxROM1 + 0x0000,  5, 1)) return 1;
// ROM_LOAD( "gb-11.bin",  0x0000, 0x1000, CRC(5d5eca1b) SHA1(d7c6b5f4d398d5e33cc411ed593d6f53a9979493) )

// ROM_REGION( 0x0120,  "proms", 0 )
if (BurnLoadRom(DrvColPROM + 0x0000,  6, 1)) return 1;
// ROM_LOAD( "prom.1a",    0x0000, 0x0020, CRC(4864a5a0) SHA1(5b49f60b085fa026d4e8d4a5ad28ee7037a8ff9c) )    /* color PROM */
if (BurnLoadRom(DrvColPROM + 0x0020,  7, 1)) return 1;
// ROM_LOAD( "prom.4c",    0x0020, 0x0100, CRC(4745b5f6) SHA1(02a7f759e9bc8089cbd9213a71bbe671f9641638) )    /* lookup table */



// these aren't used so ignore them

// ROM_REGION( 0x1000,  "user1", 0 )       /* no idea what these are */
// ROM_LOAD( "gb-01.bin",  0x0000, 0x0800, CRC(c31dba64) SHA1(15ae54b7d475ca3f0a3acc45cd8da2916c5fdef2) )
// ROM_LOAD( "gb-02.bin",  0x0800, 0x0800, CRC(65a7e284) SHA1(91e9c34dcf20608863ad5475dc0c4309971c8eee) )

// ROM_REGION( 0x8000,  "user2", 0 )       /* HD38880 code/samples? */
// ROM_LOAD( "gb-10.bin",  0x4000, 0x1000, CRC(8101915f) SHA1(c4d21b1938ea7e0d47c48e74037f005280ac101b) )
// ROM_LOAD( "gb-09.bin",  0x5000, 0x1000, CRC(619bba76) SHA1(2a2deffe6f058fc840329fbfffbc0c70a0147c14) )
// ROM_LOAD( "gb-08.bin",  0x6000, 0x1000, CRC(82f59528) SHA1(6bfa2329eb291040bfc229c56420865253b0132a) )
// ROM_LOAD( "gb-07.bin",  0x7000, 0x1000, CRC(92a9f8bf) SHA1(9231cd86f24f1e6a585c3a919add50c1f8e42a4c) )


// decode tiles here
}

ZetInit(0);


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #5 on: May 12, 2014, 09:50:21 PM »
Now we need to decode our graphics. We need this because most games have the pixels stored packed into a single byte if the pixels are only 2 bpp or 1bpp or whatever. Sometimes just because they're in a weird order. Putting them in a simple order now may take up more ram, but allows for easier drawing later.

We start with this struct -- this is how mame figures out how to decode tiles

Code: [Select]
static const gfx_layout charlayout =
{
8,8,    /* 8*8 characters */
256,    /* 256 characters */
2,      /* 2 bits per pixel */
{ 0, 4 },   /* the bitplanes are packed in one byte */
{ 0, 1, 2, 3, 8*8+0, 8*8+1, 8*8+2, 8*8+3 },
{ 7*8, 6*8, 5*8, 4*8, 3*8, 2*8, 1*8, 0*8 },
16*8    /* every char takes 16 consecutive bytes */
};

static const gfx_layout spritelayout =
{
16,16,  /* 16*16 characters */
64,     /* 64 characters */
2,      /* 2 bits per pixel */
{ 0, 4 },   /* the bitplanes are packed in one byte */
{ 0, 1, 2, 3, 24*8+0, 24*8+1, 24*8+2, 24*8+3,
16*8+0, 16*8+1, 16*8+2, 16*8+3, 8*8+0, 8*8+1, 8*8+2, 8*8+3 },
{ 39*8, 38*8, 37*8, 36*8, 35*8, 34*8, 33*8, 32*8,
7*8,  6*8,  5*8,  4*8,  3*8,  2*8,  1*8,  0*8 },
64*8    /* every char takes 64 consecutive bytes */
};

static GFXDECODE_START( gotya )
GFXDECODE_ENTRY( "gfx1", 0, charlayout,   0, 16 )
GFXDECODE_ENTRY( "gfx2", 0, spritelayout, 0, 16 )
GFXDECODE_END

This ends up being this for fba

Code: [Select]
static INT32 DrvGfxDecode()
{
// set up charlayout
INT32 Plane0[4] = { 0, 4 }; // { 0, 4 },   /* the bitplanes are packed in one byte */
INT32 XOffs0[8] = { 0, 1, 2, 3, 8*8+0, 8*8+1, 8*8+2, 8*8+3 };
INT32 YOffs0[8] = { 7*8, 6*8, 5*8, 4*8, 3*8, 2*8, 1*8, 0*8  };

// set up spritelayout
INT32 Plane1[4] = { 0, 4 }; // { 0, 4 },   /* the bitplanes are packed in one byte */
INT32 XOffs1[16] = { 0, 1, 2, 3, 24*8+0, 24*8+1, 24*8+2, 24*8+3, 16*8+0, 16*8+1, 16*8+2, 16*8+3, 8*8+0, 8*8+1, 8*8+2, 8*8+3 };
INT32 YOffs1[16] = { 39*8, 38*8, 37*8, 36*8, 35*8, 34*8, 33*8, 32*8,7*8,  6*8,  5*8,  4*8,  3*8,  2*8,  1*8,  0*8 };


// make sure to allocate a tmp that is large enough for both graphics tile sizes
UINT8 *tmp = (UINT8*)BurnMalloc(0x1000);
if (tmp == NULL) {
return 1;
}

memcpy (tmp, DrvGfxROM0, 0x1000);

GfxDecode(((0x1000 * 8) / 2) / (8 * 8), 2, 8, 8, Plane0, XOffs0, YOffs0, 16*8 /* from charlayout*/, tmp, DrvGfxROM0);

memcpy (tmp, DrvGfxROM1, 0x1000);

GfxDecode(((0x1000 * 8) / 2) / (16 * 16), 2, 16, 16, Plane1, XOffs1, YOffs1, 64*8 /* from spritelayout*/, tmp, DrvGfxROM1);

BurnFree(tmp);

return 0;
}
« Last Edit: May 13, 2014, 12:00:30 AM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #6 on: May 12, 2014, 10:06:29 PM »
Next, let's set up DrvFrame. This part can be a bit confusing/tricky. In this routine, we essentially emulate 1 frame of the game running.
In this, we have to assemble inputs, run the cpu, run the sound, ensure the colors are set up/current, and draw the frame.

for this part, we need this from MAME
Code: [Select]
MCFG_CPU_ADD("maincpu", Z80,18432000/6) /* 3.072 MHz ??? */
MCFG_CPU_PROGRAM_MAP(gotya_map)
MCFG_CPU_VBLANK_INT_DRIVER("screen", gotya_state,  irq0_line_hold)

fba is much more complicated, but allows for a lot more control/bugs

Code: [Select]




static INT32 DrvFrame()
{
watchdog++;
if (watchdog >= 180) { // arbitrary count, the watchdg is triggered so that the game resets if it glitches, hopefully fixing the problem
DrvDoReset(); // reset the game, clear watchdog in reset
}

if (DrvReset) {
DrvDoReset(); // is the reset button pressed? reset!
}

{
// assemble inputs, just need to assemble the joystick/button parts, fba does the dips for us
// each button/joy input is one bit of one of these two bytes, the bits are 1 by default (IPT_ACTIVE_LOW) or 0 (IPT_ACTIVE_HIGH)
// for this game, they are all IPT_ACTIVE_LOW, so we start with 0xff for each input (confused?)
DrvInputs[0] = 0xff;
DrvInputs[1] = 0xff;
DrvInputs[2] = 0xff;
for (INT32 i = 0; i < 8; i++) {
DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
DrvInputs[2] ^= (DrvJoy3[i] & 1) << i;
}

INT32 nCyclesTotal = (18432000/6) / 60; // MCFG_CPU_ADD("maincpu", Z80,18432000/6) / 60 (60 frames per second)

ZetOpen(0); // open the cpu
ZetRun(nCyclesTotal); // run this frame's worth of cycles (how much the cpu can process in the alotted time)
ZetSetIRQLine(0, ZET_IRQSTATUS_AUTO); // trigger and irq (these are weird!) they interrupt whatever the cpu is doing and makes
// it do something specifically set up in the cpu's program.
// this is the fba equiv to this MCFG_CPU_VBLANK_INT_DRIVER("screen", gotya_state,  irq0_line_hold)
// call the irq at "vertical blank" to tell the cpu that it has completed a frame of drawing,
// start the next one!
ZetClose(); // close the cpu

if (pBurnSoundOut) { // make sure we're outputting sound
BurnSampleRender(pBurnSoundOut, nBurnSoundLen); // actually output sound
}

if (pBurnDraw) { // make sure we're actually allowing drawing
DrvDraw(); // call the drawing routine
}

return 0;
}
« Last Edit: May 13, 2014, 12:37:02 AM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #7 on: May 12, 2014, 10:26:48 PM »
Next, let's set up the palette.

Mame does this with this routine in this particular game, this is a static palette, some do ram writes, others do weird things.

Code: [Select]

PALETTE_INIT_MEMBER(gotya_state, gotya)
{
const UINT8 *color_prom = memregion("proms")->base();
static const int resistances_rg[3] = { 1000, 470, 220 };
static const int resistances_b [2] = { 470, 220 };
double rweights[3], gweights[3], bweights[2];
int i;

/* compute the color output resistor weights */
compute_resistor_weights(0, 255, -1.0,
3, &resistances_rg[0], rweights, 0, 0,
3, &resistances_rg[0], gweights, 0, 0,
2, &resistances_b[0],  bweights, 0, 0);

/* create a lookup table for the palette */
for (i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
int r, g, b;

/* red component */
bit0 = (color_prom[i] >> 0) & 0x01;
bit1 = (color_prom[i] >> 1) & 0x01;
bit2 = (color_prom[i] >> 2) & 0x01;
r = combine_3_weights(rweights, bit0, bit1, bit2);

/* green component */
bit0 = (color_prom[i] >> 3) & 0x01;
bit1 = (color_prom[i] >> 4) & 0x01;
bit2 = (color_prom[i] >> 5) & 0x01;
g = combine_3_weights(gweights, bit0, bit1, bit2);

/* blue component */
bit0 = (color_prom[i] >> 6) & 0x01;
bit1 = (color_prom[i] >> 7) & 0x01;
b = combine_2_weights(bweights, bit0, bit1);

palette.set_indirect_color(i, rgb_t(r, g, b));
}

/* color_prom now points to the beginning of the lookup table */
color_prom += 32;

for (i = 0; i < 0x40; i++)
{
UINT8 ctabentry = color_prom[i] & 0x07;
palette.set_pen_indirect(i, ctabentry);
}
}

How these are set up is pretty interesting, MAME documents the electronics on how each color is set up and each component.

so this:

Code: [Select]
static const int resistances_rg[3] = { 1000, 470, 220 };
static const int resistances_b [2] = { 470, 220 };
double rweights[3], gweights[3], bweights[2];

compute_resistor_weights(0, 255, -1.0,
3, &resistances_rg[0], rweights, 0, 0,
3, &resistances_rg[0], gweights, 0, 0,
2, &resistances_b[0],  bweights, 0, 0);

resistances_rg[3] = { 1000, 470, 220 };

this means that to calculate the red or green components, these take 3 sub-components each.

keep in mind that we're setting this up as a 24-bit color, red is 0-255 (0xff), same for green and blue

so we can take 1000, 470, 220 and get the sum -> 1690

next we take each sub component and calculate how much of 255 it takes up

(255 * 1000) / 1690 -> 150.89
(255 * 470) / 1690 ->  70.91
(255 * 220) / 1690 -> 33.19

now let's round these up/down
151, 71, 33 -> 255!
this doesn't give mame-perfect results, but they're close enough for our purposes.

now let's do the blue sub-components
   static const int resistances_b [2] = { 470, 220 };

(255 * 470) / 690 ->  173.69
(255 * 220) / 690 -> 81.30

174, 81 -> 255!


Now let's go further, we've got each sub component set up, now let's check out how the color proms factor into this.

the first prom 32 bytes long actually selects which sub components we use for each color componet

Code: [Select]
/* red component */
bit0 = (color_prom[i] >> 0) & 0x01;
bit1 = (color_prom[i] >> 1) & 0x01;
bit2 = (color_prom[i] >> 2) & 0x01;
r = combine_3_weights(rweights, bit0, bit1, bit2);

/* green component */
bit0 = (color_prom[i] >> 3) & 0x01;
bit1 = (color_prom[i] >> 4) & 0x01;
bit2 = (color_prom[i] >> 5) & 0x01;
g = combine_3_weights(gweights, bit0, bit1, bit2);

/* blue component */
bit0 = (color_prom[i] >> 6) & 0x01;
bit1 = (color_prom[i] >> 7) & 0x01;
b = combine_2_weights(bweights, bit0, bit1);

remember 151, 71, 33 from above?
these factor in on these lines
r = combine_3_weights(rweights, bit0, bit1, bit2);
g = combine_3_weights(gweights, bit0, bit1, bit2);

r = (bit0 * 151) + (bit1 * 71) + (bit2 * 33);
g = (bit0 * 151) + (bit1 * 71) + (bit2 * 33);

now for our blue component
174, 81

b = combine_2_weights(bweights, bit0, bit1);

b = (bit 0 * 174) + (bit1 * 81)

This allows us to set up a color table, we have another color prom that selects these colors (color index/lookup)

Code: [Select]
static void DrvPaletteInit()
{
UINT32 pal[0x20];
UINT8 *color_prom = DrvColPROM;

for (INT32 i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
int r, g, b;

/* red component */
bit0 = (color_prom[i] >> 0) & 0x01;
bit1 = (color_prom[i] >> 1) & 0x01;
bit2 = (color_prom[i] >> 2) & 0x01;
r = (bit0 * 151) + (bit1 * 71) + (bit2 * 33);

/* green component */
bit0 = (color_prom[i] >> 3) & 0x01;
bit1 = (color_prom[i] >> 4) & 0x01;
bit2 = (color_prom[i] >> 5) & 0x01;
g = (bit0 * 151) + (bit1 * 71) + (bit2 * 33);

/* blue component */
bit0 = (color_prom[i] >> 6) & 0x01;
bit1 = (color_prom[i] >> 7) & 0x01;
b = (bit0 * 174) + (bit1 * 81);

// palette.set_indirect_color(i, rgb_t(r, g, b));
pal[i] = BurnHighCol(r, g, b, 0); // this function sets the colors to be whatever depth we're using, be it 24bpp, 16bpp, etc
}

/* color_prom now points to the beginning of the lookup table */
color_prom += 32;

for (INT32 i = 0; i < 0x40; i++)
{
UINT8 ctabentry = color_prom[i] & 0x07;
// palette.set_pen_indirect(i, ctabentry);
DrvPalette[i] = pal[ctabentry]; // the color index prom selects from the color table that we've set up above
}
}
« Last Edit: May 12, 2014, 11:59:24 PM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #8 on: May 12, 2014, 10:40:54 PM »
Next, let's start the drawing routines. This is for our background tiles.

Code: [Select]
TILE_GET_INFO_MEMBER(gotya_state::get_bg_tile_info)
{
int code = m_videoram[tile_index];
int color = m_colorram[tile_index] & 0x0f;

SET_TILE_INFO_MEMBER(0, code, color, 0);
}

TILEMAP_MAPPER_MEMBER(gotya_state::tilemap_scan_rows_thehand)
{
/* logical (col,row) -> memory offset */
row = 31 - row;
col = 63 - col;
return ((row) * (num_cols >> 1)) + (col & 31) + ((col >> 5) * 0x400);
}

void gotya_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(gotya_state::get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(gotya_state::tilemap_scan_rows_thehand),this), 8, 8, 64, 32);
}


Code: [Select]
static void draw_layer()
{
// first let's set up scrolling
// m_bg_tilemap->set_scrollx(0, -(*m_scroll + (m_scroll_bit_8 * 256)) - 2 * 8);
// the variable we're using is "scroll", the (m_scroll + (m_scroll_bit_8 * 256)) part is already handled

INT32 scrollx = (-(scroll) - 2 * 8) & 0x1ff;

// we use & 0x3ff because this wraps the screen around when scrolling since it is a maximum of
// 64 x 8 pixels wide (see below)

// get tilemap width / height from here
// m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(gotya_state::get_bg_tile_info),this), tilemap_mapper_delegate(FUNC(gotya_state::tilemap_scan_rows_thehand),this), 8, 8, 64, 32);
for (INT32 offs = 0; offs < 64 * 32; offs++)
{
INT32 sy = (offs / 64) * 8;
INT32 sx = (offs & 0x3f) * 8;

sx -= scrollx;
if (sx < -7) sx += 0x200; // if we're a full tile off screen, wrap back around

// get these from tilemap_scan_rows_thehand

INT32 row = (offs / 64); // sy
INT32 col = (offs & 0x3f); // sx

row = 31 - row;
col = 63 - col;

INT32 ofst = ((row) * (64 >> 1)) + (col & 31) + ((col >> 5) * 0x400);

// get these from get_bg_tile_info
INT32 code = DrvVidRAM[ofst];
INT32 color = DrvColRAM[ofst] & 0x0f;

// generic tile drawing function (tiles_generic.h)
// this is drawing 8x8 tiles, and this has the possibility of drawing partially off-screen. we will have
// to clip the tile or we will get a crash!

// pTransDraw is our temporary drawing surface
// code is the offset to the tile we want to draw -> (code * 8 * 8)
// sx & sy are offsets on the screen where we're drawing this
// color is color offset inside the palette that we're using
// this is necessary since a 2 bpp tile can only use 4 colors!
Render8x8Tile_Clip(pTransDraw, code, sx, sy, color, 2, 0, DrvGfxROM0);
}
}
« Last Edit: May 13, 2014, 11:21:10 PM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #9 on: May 12, 2014, 10:47:01 PM »
Next, let's handle this routine.

Code: [Select]
void gotya_state::draw_status_row( bitmap_ind16 &bitmap, const rectangle &cliprect, int sx, int col )
{
int row;

if (flip_screen())
{
sx = 35 - sx;
}

for (row = 29; row >= 0; row--)
{
int sy;

if (flip_screen())
sy = row;
else
sy = 31 - row;


m_gfxdecode->gfx(0)->opaque(bitmap,cliprect,
m_videoram2[row * 32 + col],
m_videoram2[row * 32 + col + 0x10] & 0x0f,
flip_screen_x(), flip_screen_y(),
8 * sx, 8 * sy);
}
}

Code: [Select]
static void draw_status_row(INT32 sx, INT32 col)
{
INT32 row;

if (flipscreen)
{
sx = 35 - sx;
}

for (row = 29; row >= 0; row--)
{
INT32 sy;

if (flipscreen)
sy = row;
else
sy = 32 - row;

INT32 code = DrvVidRAM2[row * 32 + col];
INT32 color = DrvVidRAM2[row * 32 + col + 0x10] & 0x0f;

if (flipscreen)
Render8x8Tile_FlipXY_Clip(pTransDraw, code, 8 * sx, 8 * sy, color, 2, 0, DrvGfxROM0);
else
Render8x8Tile_Clip(pTransDraw, code, 8 * sx, 8 * sy, color, 2, 0, DrvGfxROM0);
}
}

Pretty straight-forward, right?
« Last Edit: May 13, 2014, 11:22:58 PM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #10 on: May 12, 2014, 10:52:14 PM »
Now let's handle the sprites!

Code: [Select]
void gotya_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
{
UINT8 *spriteram = m_spriteram;
int offs;

for (offs = 2; offs < 0x0e; offs += 2)
{
int code = spriteram[offs + 0x01] >> 2;
int color = spriteram[offs + 0x11] & 0x0f;
int sx = 256 - spriteram[offs + 0x10] + (spriteram[offs + 0x01] & 0x01) * 256;
int sy = spriteram[offs + 0x00];

if (flip_screen())
sy = 240 - sy;


m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
code, color,
flip_screen_x(), flip_screen_y(),
sx, sy, 0);
}
}

Code: [Select]
static void draw_sprites()
{
UINT8 *spriteram = DrvSprRAM;
int offs;

for (offs = 2; offs < 0x0e; offs += 2)
{
int code = spriteram[offs + 0x01] >> 2;
int color = spriteram[offs + 0x11] & 0x0f;
int sx = 256 - spriteram[offs + 0x10] + (spriteram[offs + 0x01] & 0x01) * 256;
int sy = spriteram[offs + 0x00];

if (flipscreen)
sy = 240 - sy;

// the sprite tiles are 16x16 and if the pixel is 0 (pixel can be 0, 1, 2, 3 with a 2bpp pixel), it is clear!
// this actually only allows 3 colors per pixel!
if (flipscreen)
Render16x16Tile_Mask_Clip(pTransDraw, code, sx, sy, color, 2, 0, 0, DrvGfxROM1);
else
Render16x16Tile_Mask_FlipXY_Clip(pTransDraw, code, sx, sy, color, 2, 0, 0, DrvGfxROM1);
}
}


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #11 on: May 12, 2014, 10:56:02 PM »
Now we've got the actuall screen update function left as far as video.
Let's integrate the draw_status function too, this will just simplify things

Code: [Select]

void gotya_state::draw_status( bitmap_ind16 &bitmap, const rectangle &cliprect )
{
draw_status_row(bitmap, cliprect, 0,  1);
draw_status_row(bitmap, cliprect, 1,  0);
draw_status_row(bitmap, cliprect, 2,  2);  /* these two are blank, but I dont' know if the data comes */
draw_status_row(bitmap, cliprect, 33, 13); /* from RAM or 'hardcoded' into the hardware. Likely the latter */
draw_status_row(bitmap, cliprect, 35, 14);
draw_status_row(bitmap, cliprect, 34, 15);
}

UINT32 gotya_state::screen_update_gotya(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->set_scrollx(0, -(*m_scroll + (m_scroll_bit_8 * 256)) - 2 * 8);
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
draw_status(bitmap, cliprect);
return 0;
}

l

Code: [Select]
static INT32 DrvDraw()
{
if (DrvRecalc) {
DrvPaletteInit(); // called if the color depth is changed!
DrvRecalc = 0;
}

draw_layer();
draw_sprites();
draw_status_row(0,  1);
draw_status_row(1,  0);
draw_status_row(2,  2);  /* these two are blank, but I dont' know if the data comes */
draw_status_row(33, 13); /* from RAM or 'hardcoded' into the hardware. Likely the latter */
draw_status_row(35, 14);
draw_status_row(34, 15);

// this takes pTransDraw and adds the palette colors to it, and puts it on the screen!
BurnTransferCopy(DrvPalette);

return 0;
}


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #12 on: May 12, 2014, 11:20:45 PM »


Let's set up our inputs (I wrote a tool to do this, I find it tedious)

Code: [Select]
static INPUT_PORTS_START( gotya )
PORT_START("P1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
PORT_SERVICE( 0x10, IP_ACTIVE_LOW )
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Paper") PORT_PLAYER(1)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Scissors") PORT_PLAYER(1)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Rock") PORT_PLAYER(1)

PORT_START("P2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_DIPNAME( 0x10, 0x10, "Sound Test" )
PORT_DIPSETTING(    0x10, DEF_STR( Off ) )
PORT_DIPSETTING(    0x00, DEF_STR( On ) )
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 Paper") PORT_PLAYER(2)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Scissors") PORT_PLAYER(2)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Rock") PORT_PLAYER(2)

PORT_START("DSW")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_DIPNAME( 0x02, 0x00, DEF_STR( Cabinet ) )
PORT_DIPSETTING(    0x00, DEF_STR( Upright ) )
PORT_DIPSETTING(    0x02, DEF_STR( Cocktail ) )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START2 )
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Difficulty ) )
PORT_DIPSETTING(    0x00, DEF_STR( Easy ) )
PORT_DIPSETTING(    0x10, DEF_STR( Hard ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Bonus_Life ) )
PORT_DIPSETTING(    0x00, DEF_STR( None ) )
PORT_DIPSETTING(    0x20, "15000" )
PORT_DIPNAME( 0x40, 0x00, DEF_STR( Lives ) )
PORT_DIPSETTING(    0x00, "3" )
PORT_DIPSETTING(    0x40, "5" )
PORT_DIPNAME( 0x80, 0x80, "Game Type" )         /* Manual Says:  Before main switch on: Test Pattern */
PORT_DIPSETTING(    0x80, DEF_STR( Normal ) )   /*                After main switch on: Endless game */
PORT_DIPSETTING(    0x00, "Endless" )
INPUT_PORTS_END

Code: [Select]

Please note the numbers to the far right! these are important for our dip switches!

static struct BurnInputInfo gotyaInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy3 + 0, "p1 coin" }, // 0
{"P1 Start", BIT_DIGITAL, DrvJoy3 + 2, "p1 start" }, // 1

// PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
// BIT = (1 << 0) [0x01] -> DrvJoy + 0
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 0, "p1 left" }, // 2
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
// BIT = (1 << 1) [0x02] -> DrvJoy + 1
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 1, "p1 right" }, // 3
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 2, "p1 down" }, // 4
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 3, "p1 up" }, // 5
{"P1 Paper", BIT_DIGITAL, DrvJoy1 + 5, "p1 fire 1" }, // 6
{"P1 Scissors", BIT_DIGITAL, DrvJoy1 + 6, "p1 fire 2" }, // 7
{"P1 Rock", BIT_DIGITAL, DrvJoy1 + 7, "p1 fire 3" }, // 8

{"P2 Start", BIT_DIGITAL, DrvJoy3 + 3, "p2 start" }, // 9
{"P2 Left", BIT_DIGITAL, DrvJoy2 + 0, "p2 left" }, // 0x0a
{"P2 Right", BIT_DIGITAL, DrvJoy2 + 1, "p2 right" }, // 0x0b
{"P2 Down", BIT_DIGITAL, DrvJoy2 + 2, "p2 down" }, // 0x0c
{"P2 Up", BIT_DIGITAL, DrvJoy2 + 3, "p2 up" }, // 0x0d
{"P2 Paper", BIT_DIGITAL, DrvJoy2 + 5, "p2 fire 1" }, // 0x0e
{"P2 Scissors", BIT_DIGITAL, DrvJoy2 + 6, "p2 fire 2" }, // 0x0f
{"P2 Rock", BIT_DIGITAL, DrvJoy2 + 7, "p2 fire 3" }, // 0x10

{"Reset", BIT_DIGITAL, &DrvReset, "reset" }, // 0x11
{"Service", BIT_DIGITAL, DrvJoy1 + 4, "service" }, // 0x12
{"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" }, // 0x13
{"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" }, // 0x14
};

STDINPUTINFO(gotya)

static struct BurnDIPInfo gotyaDIPList[]=
{
// defaults!
// #0 is the offset in the input struct to where we're putting the dip info
// #1 and #2 are always the same
// #3 is the default for this dip!
// ignore the NULL
{0x13, 0xff, 0xff, 0x10, NULL },
{0x14, 0xff, 0xff, 0x6b, NULL },

// actual dips
// #0 is always 0
// #1 is always fe
// #2 is always 0
// #3 is how many dips for this selection
// #4 is the description of this switch
{0   , 0xfe, 0   ,    2, "Sound Test" },
// #0 is the offset to the input struct where this dip setting is getting stored (DrvDips + 0 for this one)
// #1 is always 1
// #2 is the bit mask
// #3 is the actual value we're using
// #4 is the description
{0x13, 0x01, 0x10, 0x10, "Off" },
{0x13, 0x01, 0x10, 0x00, "On" },


PORT_START("DSW")
PORT_DIPNAME( 0x02, 0x00, DEF_STR( Cabinet ) )
PORT_DIPSETTING(    0x00, DEF_STR( Upright ) )
PORT_DIPSETTING(    0x02, DEF_STR( Cocktail ) )

PORT_DIPNAME( 0x10, 0x00, DEF_STR( Difficulty ) )
PORT_DIPSETTING(    0x00, DEF_STR( Easy ) )
PORT_DIPSETTING(    0x10, DEF_STR( Hard ) )

PORT_DIPNAME( 0x20, 0x20, DEF_STR( Bonus_Life ) )
PORT_DIPSETTING(    0x00, DEF_STR( None ) )
PORT_DIPSETTING(    0x20, "15000" )

PORT_DIPNAME( 0x40, 0x00, DEF_STR( Lives ) )
PORT_DIPSETTING(    0x00, "3" )
PORT_DIPSETTING(    0x40, "5" )

PORT_DIPNAME( 0x80, 0x80, "Game Type" )         /* Manual Says:  Before main switch on: Test Pattern */
PORT_DIPSETTING(    0x80, DEF_STR( Normal ) )   /*                After main switch on: Endless game */
PORT_DIPSETTING(    0x00, "Endless" )


// we're not setting up flipscreen, so disable this...
// {0   , 0xfe, 0   ,    2, "Cabine" },
// {0x14, 0x01, 0x02, 0x00, "Upright" },
// {0x14, 0x01, 0x02, 0x02, "Cocktail" },

{0   , 0xfe, 0   ,    2, "Difficulty" },
{0x0d, 0x01, 0x10, 0x00, "Easy" },
{0x0d, 0x01, 0x10, 0x10, "Hard" },

{0   , 0xfe, 0   ,    2, "Bonus Life" },
{0x0d, 0x01, 0x20, 0x00, "None" },
{0x0d, 0x01, 0x20, 0x20, "15000" },

{0   , 0xfe, 0   ,    2, "Lifes" },
{0x0d, 0x01, 0x40, 0x00, "3" },
{0x0d, 0x01, 0x40, 0x40, "5" },

{0   , 0xfe, 0   ,    2, "Game Type" },
{0x0d, 0x01, 0x80, 0x80, "Endless" },
{0x0d, 0x01, 0x80, 0x00, "Normal" },
};

STDDIPINFO(gotya)


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #13 on: May 12, 2014, 11:28:12 PM »
We're almost there! Now let's add all of our variables at the top of our file we've been working in.

Code: [Select]
static UINT8 *AllMem;
static UINT8 *MemEnd;
static UINT8 *AllRam;
static UINT8 *RamEnd;
static UINT8 *DrvZ80ROM;
static UINT8 *DrvGfxROM0;
static UINT8 *DrvGfxROM1;
static UINT8 *DrvColPROM;
static UINT8 *DrvZ80RAM;
static UINT8 *DrvVidRAM;
static UINT8 *DrvColRAM;
static UINT8 *DrvVidRAM2;
static UINT8 *DrvSprRAM;

static UINT32 *DrvPalette;
static UINT8 DrvRecalc;

static INT32 scroll;
static INT32 flipscreen;
static INT32 watchdog;

static UINT8 DrvJoy1[8];
static UINT8 DrvJoy2[8];
static UINT8 DrvJoy3[8];
static UINT8 DrvDips[2];
static UINT8 DrvInputs[3];
static UINT8 DrvReset;

above that, let's do our includes...

We always do this in fba
#include "tiles_generic.h"
this game uses a z80
#include "z80_intf.h"
this game uses samples
#include "samples.h"
« Last Edit: May 13, 2014, 12:02:27 AM by iq_132 »


Offline iq_132

  • Administrator
  • *****
  • Posts: 3728
  • Karma: +411/-0
  • Definitely not Dink!
    • NeoSource
Re: Care to follow along?
« Reply #14 on: May 12, 2014, 11:44:19 PM »
Now let's do our rom struct

Code: [Select]

ROM_START( thehand )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "hand6.bin",  0x0000, 0x1000, CRC(a33b806c) SHA1(1e552af5362e7b003f55e78bb59589e1db55557c) )
ROM_LOAD( "hand5.bin",  0x1000, 0x1000, CRC(89bcde82) SHA1(d074bb6a1975160eb533d5fd9289170a68209046) )
ROM_LOAD( "hand4.bin",  0x2000, 0x1000, CRC(c6844a83) SHA1(84e220dce3f5ddee9dd0377f3bebdd4027fc9108) )
ROM_LOAD( "gb-03.bin",  0x3000, 0x1000, CRC(f34d90ab) SHA1(bec5f6a34a273f308083a280f2b425d9c273c69b) )

ROM_REGION( 0x1000,  "gfx1", 0 )    /* characters */
ROM_LOAD( "hand12.bin", 0x0000, 0x1000, CRC(95773b46) SHA1(db8d7ace4eafd4c72edfeff6003ca6e96e0239b5) )

ROM_REGION( 0x1000,  "gfx2", 0 )    /* sprites */
ROM_LOAD( "gb-11.bin",  0x0000, 0x1000, CRC(5d5eca1b) SHA1(d7c6b5f4d398d5e33cc411ed593d6f53a9979493) )

ROM_REGION( 0x0120,  "proms", 0 )
ROM_LOAD( "prom.1a",    0x0000, 0x0020, CRC(4864a5a0) SHA1(5b49f60b085fa026d4e8d4a5ad28ee7037a8ff9c) )    /* color PROM */
ROM_LOAD( "prom.4c",    0x0020, 0x0100, CRC(4745b5f6) SHA1(02a7f759e9bc8089cbd9213a71bbe671f9641638) )    /* lookup table */

ROM_REGION( 0x1000,  "user1", 0 )       /* no idea what these are */
ROM_LOAD( "hand1.bin",  0x0000, 0x0800, CRC(ccc537e0) SHA1(471fd49225aa14b91d085178e1b58b6c4ae76481) )
ROM_LOAD( "gb-02.bin",  0x0800, 0x0800, CRC(65a7e284) SHA1(91e9c34dcf20608863ad5475dc0c4309971c8eee) )

ROM_REGION( 0x8000,  "user2", 0 )       /* HD38880 code/samples? */
ROM_LOAD( "gb-10.bin",  0x4000, 0x1000, CRC(8101915f) SHA1(c4d21b1938ea7e0d47c48e74037f005280ac101b) )
ROM_LOAD( "gb-09.bin",  0x5000, 0x1000, CRC(619bba76) SHA1(2a2deffe6f058fc840329fbfffbc0c70a0147c14) )
ROM_LOAD( "gb-08.bin",  0x6000, 0x1000, CRC(82f59528) SHA1(6bfa2329eb291040bfc229c56420865253b0132a) )
ROM_LOAD( "hand7.bin",  0x7000, 0x1000, CRC(fbf1c5de) SHA1(dd3181a8da1972e3c997678bb868256a10f33d04) )
ROM_END

GAME( 1981, thehand, 0,       gotya, gotya, driver_device, 0, ROT270, "T.I.C.",      "The Hand", GAME_IMPERFECT_SOUND | GAME_SUPPORTS_SAVE )


in fba we pull a lot of information to put together our struct


Code: [Select]
// The Hand

static struct BurnRomInfo thehandRomDesc[] = {
{ "hand6.bin",  0x1000, 0xa33b806c, 0 | BRF_PRG | BRF_ESS }, //  0 Z80 Code
{ "hand5.bin",  0x1000, 0x89bcde82, 0 | BRF_PRG | BRF_ESS }, //  1
{ "hand4.bin",  0x1000, 0xc6844a83, 0 | BRF_PRG | BRF_ESS }, //  2
{ "gb-03.bin",  0x1000, 0xf34d90ab, 0 | BRF_PRG | BRF_ESS }, //  3

{ "hand12.bin", 0x1000, 0x95773b46, 1 | BRF_GRA },           //  4 Background Tiles

{ "gb-11.bin",  0x1000, 0x5d5eca1b, 2 | BRF_GRA },           //  5 Sprites

{ "prom.1a",    0x0020, 0x4864a5a0, 3 | BRF_GRA },           //  6 Colors
{ "prom.4c",    0x0100, 0x4745b5f6, 3 | BRF_GRA },           //  7 Color Lookup table

{ "hand1.bin",  0x0800, 0xccc537e0, 4 | BRF_OPT },           //  8 ??
{ "gb-02.bin",  0x0800, 0x65a7e284, 4 | BRF_OPT },           //  9

{ "gb-10.bin",  0x1000, 0x8101915f, 4 | BRF_OPT },           // 10 HD38880 code
{ "gb-09.bin",  0x1000, 0x619bba76, 4 | BRF_OPT },           // 11
{ "gb-08.bin",  0x1000, 0x82f59528, 4 | BRF_OPT },           // 12
{ "hand7.bin",  0x1000, 0xfbf1c5de, 4 | BRF_OPT },           // 13
};

STD_ROM_PICK(thehand)
STD_ROM_FN(thehand)

struct BurnDriver BurnDrvThehand = {
"thehand", NULL, NULL, "thehand", "1981",
"The Hand\0", NULL, "T.I.C.", "MISCELLANEOUS",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 2, HARDWARE_MISC_PRE90S, GBF_PUZZLE, 0,
NULL, thehandRomInfo, thehandRomName, thehandSampleInfo, thehandSampleName, gotyaInputInfo, gotyaDIPInfo,
DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 64,
288, 224, 4, 3 // MCFG_SCREEN_VISIBLE_AREA(0, 36*8-1, 2*8, 30*8-1)
};
« Last Edit: May 13, 2014, 12:08:38 AM by iq_132 »