Existen una docena larga de versiones de Frogger...
Código: Seleccionar todo
froggers Frog
cfrogger Frogger (Coleco)
frogf Frog (Falcon bootleg)
frogg Frog (Galaxian hardware)
frogger Frogger
froggeram Frogger (bootleg on Amigo? hardware)
froggermc Frogger (Moon Cresta hardware)
froggers1 Frogger (Sega set 1)
froggers2 Frogger (Sega set 2)
froggerv Frogger (Videotron bootleg)
froggrs Frogger (Scramble hardware)
frogs Frogs
quaak Quaak (bootleg of Frogger)
Esas son las versiones que soporta el MAME (en la versión 0.164, al menos).
La que nos interesa es la que tiene "frogger" como controlador. En el código fuente de
galaxian.cpp viene la definición de las máquinas para el hardware de la placa base del juego Galaxian y sobre el que se crearon algunos juegos más:
Línea 35:
Código: Seleccionar todo
****************************************************************************
Schematics are known to exist for these games:
* Galaxian
* Moon Alien Part 2
* King and Balloon
* Moon Cresta
* Moon Shuttle
* Frogger
* Amidar
* Turtles
* Scramble
* The End
* Super Cobra
* Dark Planet
* Lost Tomb
* Dambusters
****************************************************************************
Pero hay que prestar atención a los detalles, porque hay varios Frogger. Hay uno incluso basado en el hardware del juego MoonCresta.
Entonces, en el código, lo primero es ver el mapa de memoria por defecto. Línea 1496:
Código: Seleccionar todo
/*************************************
*
* Memory maps
*
*************************************/
/*
0000-3fff
4000-7fff
4000-47ff -> RAM read/write (10 bits = 0x400)
4800-4fff -> n/c
5000-57ff -> /VRAM RD or /VRAM WR (10 bits = 0x400)
5800-5fff -> /OBJRAM RD or /OBJRAM WR (8 bits = 0x100)
6000-67ff -> /SW0 or /DRIVER
6800-6fff -> /SW1 or /SOUND
7000-77ff -> /DIPSW or LATCH
7800-7fff -> /WDR or /PITCH
/DRIVER: (write 6000-67ff)
D0 = data bit
A0-A2 = decoder
6000 -> 1P START
6001 -> 2P START
6002 -> COIN LOCKOUT
6003 -> COIN COUNTER
6004 -> 1M resistor (controls 555 timer @ 9R)
6005 -> 470k resistor (controls 555 timer @ 9R)
6006 -> 220k resistor (controls 555 timer @ 9R)
6007 -> 100k resistor (controls 555 timer @ 9R)
/SOUND: (write 6800-6fff)
D0 = data bit
A0-A2 = decoder
6800 -> FS1 (enables 555 timer at 8R)
6801 -> FS2 (enables 555 timer at 8S)
6802 -> FS3 (enables 555 timer at 8T)
6803 -> HIT
6804 -> n/c
6805 -> FIRE
6806 -> VOL1
6807 -> VOL2
LATCH: (write 7000-77ff)
D0 = data bit
A0-A2 = decoder
7000 -> n/c
7001 -> NMI ON
7002 -> n/c
7003 -> n/c
7004 -> STARS ON
7005 -> n/c
7006 -> HFLIP
7007 -> VFLIP
/PITCH: (write 7800-7fff)
loads latch at 9J
*/
El hardware del Frogger tiene sus peculiaridades, de tal manera que tiene su propio mapa. Línea 1952:
Código: Seleccionar todo
/* map derived from schematics */
void galaxian_state::frogger_map(address_map &map)
{
map.unmap_value_high();
map(0x0000, 0x3fff).rom();
map(0x8000, 0x87ff).ram();
map(0x8800, 0x8800).mirror(0x07ff).r("watchdog", FUNC(watchdog_timer_device::reset_r));
map(0xa800, 0xabff).mirror(0x0400).ram().w(FUNC(galaxian_state::galaxian_videoram_w)).share("videoram");
map(0xb000, 0xb0ff).mirror(0x0700).ram().w(FUNC(galaxian_state::galaxian_objram_w)).share("spriteram");
map(0xb808, 0xb808).mirror(0x07e3).w(FUNC(galaxian_state::irq_enable_w));
map(0xb80c, 0xb80c).mirror(0x07e3).w(FUNC(galaxian_state::galaxian_flip_screen_y_w));
map(0xb810, 0xb810).mirror(0x07e3).w(FUNC(galaxian_state::galaxian_flip_screen_x_w));
map(0xb818, 0xb818).mirror(0x07e3).w(FUNC(galaxian_state::coin_count_0_w)); /* IOPC7 */
map(0xb81c, 0xb81c).mirror(0x07e3).w(FUNC(galaxian_state::coin_count_1_w)); /* POUT1 */
map(0xc000, 0xffff).rw(FUNC(galaxian_state::frogger_ppi8255_r), FUNC(galaxian_state::frogger_ppi8255_w));
}
La segunda CPU es la que genera el sonido. Su mapa de memoria es mucho más sencillo. Línea 2228:
Código: Seleccionar todo
// Konami Frogger with 1 x AY-8910A
void galaxian_state::frogger_sound_map(address_map &map)
{
map.global_mask(0x7fff);
map(0x0000, 0x1fff).rom();
map(0x4000, 0x43ff).mirror(0x1c00).ram();
map(0x6000, 0x6fff).mirror(0x1000).w(FUNC(galaxian_state::konami_sound_filter_w));
}
Quedan los puertos de E/S, que suelen estar mapeados en el espacio de direcciones. Línea 4372:
Código: Seleccionar todo
static INPUT_PORTS_START( frogger )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY PORT_COCKTAIL
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* 1P shoot2 - unused */
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* 1P shoot1 - unused */
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_START("IN1")
PORT_DIPNAME( 0x03, 0x00, DEF_STR( Lives ) )
PORT_DIPSETTING( 0x00, "3" )
PORT_DIPSETTING( 0x01, "5" )
PORT_DIPSETTING( 0x02, "7" )
PORT_DIPSETTING( 0x03, "256 (Cheat)")
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* 2P shoot2 - unused */
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) /* 2P shoot1 - unused */
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY PORT_COCKTAIL
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY PORT_COCKTAIL
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START1 )
PORT_START("IN2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_COCKTAIL
PORT_DIPNAME( 0x06, 0x00, DEF_STR( Coinage ) )
PORT_DIPSETTING( 0x02, "A 2/1 B 2/1 C 2/1" )
PORT_DIPSETTING( 0x04, "A 2/1 B 1/3 C 2/1" )
PORT_DIPSETTING( 0x00, "A 1/1 B 1/1 C 1/1" )
PORT_DIPSETTING( 0x06, "A 1/1 B 1/6 C 1/1" )
PORT_DIPNAME( 0x08, 0x00, DEF_STR( Cabinet ) )
PORT_DIPSETTING( 0x00, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x08, DEF_STR( Cocktail ) )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN3") /* need for some PPI accesses */
PORT_BIT( 0xff, 0x00, IPT_UNUSED )
INPUT_PORTS_END
El programa empieza con la definición de la máquina en 6313:
Código: Seleccionar todo
MACHINE_CONFIG_START(galaxian_state::frogger)
konami_base(config);
konami_sound_1x_ay8910(config);
/* alternate memory map */
MCFG_DEVICE_MODIFY("maincpu")
MCFG_DEVICE_PROGRAM_MAP(frogger_map)
MACHINE_CONFIG_END
5977:
Código: Seleccionar todo
void galaxian_state::konami_base(machine_config &config)
{
galaxian_base(config);
I8255A(config, m_ppi8255[0]);
m_ppi8255[0]->in_pa_callback().set_ioport("IN0");
m_ppi8255[0]->in_pb_callback().set_ioport("IN1");
m_ppi8255[0]->in_pc_callback().set_ioport("IN2");
m_ppi8255[0]->out_pc_callback().set(FUNC(galaxian_state::konami_portc_0_w));
I8255A(config, m_ppi8255[1]);
m_ppi8255[1]->out_pa_callback().set(m_soundlatch, FUNC(generic_latch_8_device::write));
m_ppi8255[1]->out_pb_callback().set(FUNC(galaxian_state::konami_sound_control_w));
m_ppi8255[1]->in_pc_callback().set_ioport("IN3");
m_ppi8255[1]->out_pc_callback().set(FUNC(galaxian_state::konami_portc_1_w));
}
O sea, que los IN0..2 son puertos que leemos desde el chip 8255. Bueno, son dos:
Código: Seleccionar todo
12594 /* Frogger based hardware: 2nd Z80, AY-8910A, 2 8255 PPI for I/O, custom background */
5938:
Código: Seleccionar todo
MACHINE_CONFIG_START(galaxian_state::galaxian_base)
/* basic machine hardware */
MCFG_DEVICE_ADD("maincpu", Z80, GALAXIAN_PIXEL_CLOCK/3/2)
MCFG_DEVICE_PROGRAM_MAP(galaxian_map)
WATCHDOG_TIMER(config, "watchdog").set_vblank_count("screen", 8);
/* video hardware */
MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_galaxian)
MCFG_PALETTE_ADD("palette", 32)
MCFG_PALETTE_INIT_OWNER(galaxian_state, galaxian)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_RAW_PARAMS(GALAXIAN_PIXEL_CLOCK, GALAXIAN_HTOTAL, GALAXIAN_HBEND, GALAXIAN_HBSTART, GALAXIAN_VTOTAL, GALAXIAN_VBEND, GALAXIAN_VBSTART)
MCFG_SCREEN_UPDATE_DRIVER(galaxian_state, screen_update_galaxian)
MCFG_SCREEN_VBLANK_CALLBACK(WRITELINE(*this, galaxian_state, vblank_interrupt_w))
/* sound hardware */
SPEAKER(config, "speaker").front_center();
MACHINE_CONFIG_END
1588:
Código: Seleccionar todo
void galaxian_state::galaxian_map(address_map &map)
{
galaxian_map_base(map);
galaxian_map_discrete(map);
}
1558:
Código: Seleccionar todo
void galaxian_state::galaxian_map_discrete(address_map &map)
{
map(0x6004, 0x6007).mirror(0x07f8).w("cust", FUNC(galaxian_sound_device::lfo_freq_w));
map(0x6800, 0x6807).mirror(0x07f8).w("cust", FUNC(galaxian_sound_device::sound_w));
map(0x7800, 0x7800).mirror(0x07ff).w("cust", FUNC(galaxian_sound_device::pitch_w));
}
void galaxian_state::galaxian_map_base(address_map &map)
{
map.unmap_value_high();
map(0x0000, 0x3fff).rom();
map(0x4000, 0x43ff).mirror(0x0400).ram();
map(0x5000, 0x53ff).mirror(0x0400).ram().w(FUNC(galaxian_state::galaxian_videoram_w)).share("videoram");
map(0x5800, 0x58ff).mirror(0x0700).ram().w(FUNC(galaxian_state::galaxian_objram_w)).share("spriteram");
map(0x6000, 0x6000).mirror(0x07ff).portr("IN0");
map(0x6000, 0x6001).mirror(0x07f8).w(FUNC(galaxian_state::start_lamp_w));
map(0x6002, 0x6002).mirror(0x07f8).w(FUNC(galaxian_state::coin_lock_w));
map(0x6003, 0x6003).mirror(0x07f8).w(FUNC(galaxian_state::coin_count_0_w));
//AM_RANGE(0x6004, 0x6007) AM_MIRROR(0x07f8) AM_DEVWRITE("cust", galaxian_sound_device, lfo_freq_w)
map(0x6800, 0x6800).mirror(0x07ff).portr("IN1");
//AM_RANGE(0x6800, 0x6807) AM_MIRROR(0x07f8) AM_DEVWRITE("cust", galaxian_sound_device, sound_w)
map(0x7000, 0x7000).mirror(0x07ff).portr("IN2");
map(0x7001, 0x7001).mirror(0x07f8).w(FUNC(galaxian_state::irq_enable_w));
map(0x7004, 0x7004).mirror(0x07f8).w(FUNC(galaxian_state::galaxian_stars_enable_w));
map(0x7006, 0x7006).mirror(0x07f8).w(FUNC(galaxian_state::galaxian_flip_screen_x_w));
map(0x7007, 0x7007).mirror(0x07f8).w(FUNC(galaxian_state::galaxian_flip_screen_y_w));
//AM_RANGE(0x7800, 0x7800) AM_MIRROR(0x07ff) AM_DEVWRITE("cust", galaxian_sound_device, pitch_w)
map(0x7800, 0x7800).mirror(0x07ff).r("watchdog", FUNC(watchdog_timer_device::reset_r));
}
Entonces, los puertos corresponden a:
Que coincide con lo descrito en la línea 1496. Pero había que hacer toda esta averiguación para estar seguros.
La descripción del vídeo está en el archivo
video/galaxian.cpp.
Lo interesante está en la línea 132 y siguientes:
Código: Seleccionar todo
From this, you can see the object RAM layout looks like:
objram[40] = vertical position of sprite 0
objram[41] = picture number and H/V flip of sprite 0
objram[42] = color of sprite 0
objram[43] = horizontal position of sprite 0
objram[61] = vertical position of shell 0
objram[63] = horizontal count until shell 0 starts rendering
pero hay que leerse todos esos párrafos, para saber todas las posiciones de los 8 sprites.
Entonces, a tu pregunta:
Bubu escribió:Tengo pendiente comprender qué es el indicador en $83FE, y qué se almacena en ese array $8300, $8301, $8302, etc
yo creo que son posiciones de la RAM, así que lo que estás viendo son variables del programa.
Comienza la ingeniería inversa...