Desentrañando los misterios del Frogger (¡¡croac!!)

Foro dedicado a la programación en todo tipo de sistemas clásicos.
Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 01:52

Bueno, según mis últimos estudios, el tema de puertos queda como sigue:

IN
$E000
$E002
$E004


OUT
$D000
$D002


Esto es rarro, rarro, rarro...
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 02:09

Dejo lo de los puertos pa aluego, porque la noche me confunde. Procedo con la ROM en sí, la rutina inicial:

Código: Seleccionar todo

0000: 3A 00 40       LD      A,($4000)       ; Lee una posible expansión de la ROM
0003: FE 55          CP      $55             ; Si se encuentra el valor $55
0005: CA 01 40       JP      Z,$4001         ; Salta a dicha ROM
0008: 3A 00 88       LD      A,(watchdog)    ; Si no, lee el watchdog
000B: 31 00 88       LD      SP,$8800        ; Sitúa la pila al final de la RAM
000E: C3 A3 02       JP      Initialize      ; Salta a la rutina de inicialización


La ROM del Frogger llega hasta $3FFF, por tanto si alguien ha colocado el valor $55 en la posición $4000, sisnifica que hay una expansión de la ROM, u otra ROM ahí, y lo que hace esto en ese caso es irse p'allá. Si no, sigue su ejecución normal: lee el watchdog (pa que no se resetee el micro), sitúa la pila en $8800 que es el final (+1) de la RAM. La RAM de este juego va de $8000 a $87FF. Y por último, salta a "Initialize".

¿Qué diablos podría ser eso de la expansión de la ROM? A mí se m'ocurre un pograma de chequeo durante el desarrollo del Frogger. Así las cosas, si querían ejecutar ese pograma sólo tenían que meter el valor $55 en la posición $4000 e iniciar la placa. Si lo querían ejecutar en modo normal, pos quitaban ese valor (o quitaban direstamente el chip de esa ROM extendida)
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 02:28

Pasamos a continuación a los diversos servicios que ofrece la ROM (RST00, RST08, etc). El caso de RST00 ya se ha visto, que es el servicio "boot". El siguiente servicio que se ofrece es RST18:

Código: Seleccionar todo

; Servicio RST18
; Graba el valor de A en la posición RAM almacenada en ($8300)+1
; pero si ($83FF)=0 no hace nada
; IN: A = valor a grabar
; OUT: C = A; No modifica más registros

0018: 4F             LD      C,A             
0019: 3A FE 83       LD      A,($83FE)       
001C: B7             OR      A               
001D: C8             RET     Z               
001E: E5             PUSH    HL             
001F: 21 00 83       LD      HL,$8300       
0022: 34             INC     (HL)           
0023: 7E             LD      A,(HL)         
0024: 6F             LD      L,A             
0025: 71             LD      (HL),C    ; H=$83, L=($8300)+1     
0026: E1             POP     HL             
0027: C9             RET                   


Tengo pendiente comprender qué es el indicador en $83FE, y qué se almacena en ese array $8300, $8301, $8302, etc
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
explorer
MSX Turbo R
MSX Turbo R
Mensajes: 398
Registrado: 11 May 2014, 17:10
Sistema Favorito: Atari ST
primer_sistema: Atari 800XL/600XL
consola_favorita: Atari 2600
Primera consola: Atari 2600
Ubicación: Valladolid, España
Gracias dadas: 2 veces
Gracias recibidas: 138 veces
Contactar:

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor explorer » 21 Nov 2018, 06:47

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:

Código: Seleccionar todo

IN0: 0x6000
IN1: 0x6800
IN2: 0x7000

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...

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 09:58

explorer escribió:Existen una docena larga de versiones de Frogger...


Yo utilizo la parent, que se llama "frogger".


explorer escribió:La que nos interesa es la que tiene "frogger" como controlador.


Efestivamente, esa es la que uso.


explorer escribió:Pero hay que prestar atención a los detalles, porque hay varios Frogger. Hay uno incluso basado en el hardware del juego MoonCresta.


La rom basada en el hardware del MoonCresta se llama froggrmc (mc=moon cresta), pero yo uso la "froggerr 8-)


explorer escribió:Entonces, en el código, lo primero es ver el mapa de memoria por defecto. Línea 1496:


Ah, ok, que te referías a la línea 1496 del archivo del Galaxian. Sí, lo estoy mirando. Pero la información del mapeado viene también en el archivo del mismo "Frogger". Aun así, estoy mirando ambos archivos.

Código: Seleccionar todo

/*
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
*/


Aquí vemos que p.ej. $6000 indica 1P start. Ahora vemos más adelante algo incongruente.


explorer escribió:Entonces, los puertos corresponden a:

Código: Seleccionar todo

IN0: 0x6000
IN1: 0x6800
IN2: 0x7000

Que coincide con lo descrito en la línea 1496. Pero había que hacer toda esta averiguación para estar seguros.


Aquí se indica que el puerto 0 (IN0) se corresponde con la dirección $6000, pero más arriba se decía que $6000 se corresponde con 1PSTART. ¿Entóns? ¿Es un puerto cuya lestura de 8 bits indica los diferentes estados de los inputs, o es sólo 1PSTART? Yo pienso que es un puerto completo, pero entóns qué sisnifica lo de que está asociado a 1PSTART.

explorer escribió:
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...


Sí, pero son variables especiales, ya que se ha creado el servicio RST18 sólo pa llenarlas. Además, se llenan secuencialmente hacia adelante. Es como una pila pero de 8 bits. Además, si ($83FE)=0 el servicio RST18 no hace nada. Es muy curioso...
¡¡Eso es, vamos con la reverse engineering!!
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
explorer
MSX Turbo R
MSX Turbo R
Mensajes: 398
Registrado: 11 May 2014, 17:10
Sistema Favorito: Atari ST
primer_sistema: Atari 800XL/600XL
consola_favorita: Atari 2600
Primera consola: Atari 2600
Ubicación: Valladolid, España
Gracias dadas: 2 veces
Gracias recibidas: 138 veces
Contactar:

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor explorer » 21 Nov 2018, 11:20

Bubu escribió:Aquí se indica que el puerto 0 (IN0) se corresponde con la dirección $6000, pero más arriba se decía que $6000 se corresponde con 1PSTART. ¿Entóns? ¿Es un puerto cuya lestura de 8 bits indica los diferentes estados de los inputs, o es sólo 1PSTART? Yo pienso que es un puerto completo, pero entóns qué sisnifica lo de que está asociado a 1PSTART.

Los puertos están descritos en la sección INPUT_PORTS_START( frogger )

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 12:20

Esa función INPUT_PORTS_START describe muy bien la utilidad de cada bit de cada puerto, pero lo que no encuentro (de momento) es a qué dirección de memoria están mapeados cada puerto.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 21 Nov 2018, 13:18

Seguimos con los servicios RST. Ahora le toca a RST28:

Código: Seleccionar todo

; Imprime en pantalla un texto
; DE = dirección donde se almacena el texto
; HL = dirección V-RAM de la pantalla
; B = número de caracteres
PrintString:
0028: 1A             LD      A,(DE)          ; Lee el carácter a imprimir
0029: 77             LD      (HL),A          ; Lo imprime en pantalla
002A: 7D             LD      A,L             ; Calcula la siguiente columna
002B: D6 20          SUB     $20             
002D: 6F             LD      L,A             
002E: 30 01          JR      NC,$31          ; Si es $20, ha llegado al final de la fila
0030: 25             DEC     H               ; en cuyo caso sigue en la fila siguiente
0031: 13             INC     DE              ; Apunta al siguiente carácter
0032: 10 F4          DJNZ    PrintString     ; Sigue imprimendo
0034: C9             RET   


Se trata de una rutina para imprimir caracteres en pantalla. Incluso si el texto no cabe en una fila, sigue imprimendo en la columna 0 de la siguiente fila. La V-RAM en el Frogger está formada por 32 columnas y 28 filas, empezando en $A800:

Código: Seleccionar todo

Fila0: $A800 - $A801 - $A802 ... - $A81F
Fila1: $A820 - $A821 - $A822 ... - $A83F
Fila2: $A840 - $A841 - $A842 ... - $A85F
...
Fila27:$AB60 - $AB61 - $AB62 ... - $AB7F


Esto sería con un monitor horizontal. Pero como el Frogger es un juego vertical, sisnifica que tié el monitor girado 90º (en sentido horario), y por tanto las filas son columnas y las columnas filas:

Código: Seleccionar todo

Fila0: $AB60 - $AB40 - $AB20 ... - $A800
Fila1: $AB61 - $AB41 - $AB21 ... - $A801
Fila2: $AB62 - $AB42 - $AB22 ... - $A802
...
Fila31:$AB7F - $AB5F - $AB3F ... - $A81F


Por esto, esta rutina RST28 lo que hace para pasar a la siguiente columna es restar $20
Última edición por Bubu el 23 Nov 2018, 00:37, editado 1 vez en total.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 22 Nov 2018, 00:39

Vamos con el siguiente y último servicio, el RST38:

Código: Seleccionar todo

ClearScreen:
0038: 11 10 20       LD      DE,$2010        ; D=32 columnas, E=carácter $10 que es el espacio
003B: 21 00 A8       LD      HL,$A800        ; HL apunta a la V-RAM
003E: 06 20          LD      B,$20           ; 32 caracteres por columna
0040: 73             LD      (HL),E          ; Colocamos un espacio
0041: 23             INC     HL              ; Siguiente V-RAM
0042: 10 FC          DJNZ    $40             ; Repite las 32 veces (llena toda la columna)
0044: 0E 15          LD      C,$15           ; Va a realizar una pausa
0046: 10 FE          DJNZ    $46             
0048: 0D             DEC     C               
0049: 20 FB          JR      NZ,$46         
004B: 15             DEC     D               ; Repetir para todas las 32 (?) columnas
004C: 20 F0          JR      NZ,$3E         
004E: C9             RET                     


Se trata del típico CLS o borrar la pantalla. Pero este CLS mete una pausa en cá columna (la pausa es decrementar $15 veces 1 byte al completo, uséase, $15x$FF veces). Esta pausa se nota p.ej. na más arrancar el juego: sale la pantalla llena de ceros, y entóns se empieza a borrar de derecha a izquerda.
Poco más hay que decir aquí, salvo que de nuevo, como sabemos, la pantalla al seer vertical borra por columnas y no por filas.
Lo que sí veo rarro es que borra un cuadrado de 32x32, pero la V-RAM es de 32x28. Habrá que ver qué hace al meter un $10 en las dirersiones que no son de la V-RAM. Es decir, sigue metiendo el $10 en $AB80, $AB81, ..., $ABBF, las cuales están fuera de pantalla.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 886
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 20 veces
Gracias recibidas: 60 veces

Re: Desentrañando los misterios del Frogger (¡¡croac!!)

Mensajepor Bubu » 22 Nov 2018, 01:21

Bueno, como resumen de lo visto hasta ahora:

Código: Seleccionar todo

$0000 : boot
$0018 : RST18 - Push A (?)
$0028 : RST28 - PrintSting
$0038 : RST38 - ClearScreen


Como no tengo claro que el servicio RST18 sea un "PUSH A" (desde luego el código es totalmente un PUSH A), vamos a ver si averiguamos dónde estará el anti-RST18, es decir, el "POP A". Lo encuentro en la dirección $07AC:


Código: Seleccionar todo

07AC: 21 00 83       LD      HL,$8300        ; HL apunta al valor del stack pointer de 8 bits
07AF: 7E             LD      A,(HL)          ; Tomamos ese valor
07B0: B7             OR      A               ; Si es 0, no hay nada en la pila
07B1: C8             RET     Z               ; y retornamos
07B2: 35             DEC     (HL)            ; Si no, decrementamos el valor del stack pointer
07B3: 4F             LD      C,A             ; Salvamos el valor de A (stack pointer)
07B4: 2C             INC     L               ; Pasamos al primer elemento de la pila, que está en $8301
07B5: 7E             LD      A,(HL)          ; Obtenemos el valor
07B6: CD 94 07       CALL    $0794           ; Rutina que envía ese valor al PPI8255 + 1000 (???)
07B9: 54             LD      D,H             ; DE apunta al primer elemento de la pila
07BA: 5D             LD      E,L             
07BB: 2C             INC     L               ; HL apunta al segundo elemento de la pila
07BC: 06 00          LD      B,$00           ; B=0 para que itere 256 veces
07BE: ED B0          LDIR                    ; Desplazamos toda la pila a la izquierda 1 posición
07C0: C9             RET                     


Como veis, esta es la típica rutina de una pila LILO de 8 bits. Con RST18 se van metiendo bytes en esta pila, y con esta rutina sacamos el valor más antiguo y se envía al PPI8255 (lo cual nu sé aún qué hace). Una vez enviado al PPI, se desplaza la pila a la izquierda.

Observemos ahora qué hace la llamada a $0794:

Código: Seleccionar todo

0794: 32 00 D0       LD      (PPI8255+1000),A;Enviamos el valor A (el valor más antiguo que se metió en la pila) al PPI+1000
0797: 3A D9 83       LD      A,($83D9)   ;    Tomamos el valor en $83D9 (???)
079A: E6 F7          AND     $F7             ; Máscara para los 5 bits de más peso (%11111000)
079C: 32 02 D0       LD      (PPI8255+1002),A;Almacenamos ese valor en el PPI+1002
079F: 00             NOP                     
07A0: 00             NOP                     
07A1: 00             NOP                     
07A2: 00             NOP                     
07A3: 3A D9 83       LD      A,($83D9)       ; Volvemos a tomar el valor en $83D9 (???)
07A6: F6 08          OR      $08             ; Ponemos el bit 3 a 1 (%00001000)
07A8: 32 02 D0       LD      (PPI8255+1002),A;Almacenamos ese valor en el PPI+1002
07AB: C9             RET                     



Necesito saber qué es eso del PPI+1000, PPI+1002, etc. Parecen ser los puertos, quizás es la comunicación con el Z80 para el sonido.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 10 invitados