<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Manuel Abadia's ASP.NET stuff - Games</title>
    <link>http://www.manuelabadia.com/blog/</link>
    <description />
    <language>en-us</language>
    <copyright>Manuel Abadia</copyright>
    <lastBuildDate>Mon, 12 May 2008 09:13:01 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>blogcomments@manuelabadia.com</managingEditor>
    <webMaster>blogcomments@manuelabadia.com</webMaster>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=51ac1b35-5246-4e8c-9ee6-41334480a54e</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=51ac1b35-5246-4e8c-9ee6-41334480a54e</wfw:commentRss>
      <slash:comments>32</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
 
</p>
        <p>
World Rally emulation is complete. I implemented priorities (that were trickier than
I thought), shadows/highlights and a few missing bits in the video hardware. Here
are some screenshots of the finished driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border="0" />
        </p>
        <p>
The game is fully playable from beginning to end without any problem as far as I can
tell. I thought there was a bug in the video hardware emulation somewhere when I saw
this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border="0" />
        </p>
        <p>
So I plugged my PCB and compared it to the driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border="0" />
        </p>
        <p>
The problem is also in the original arcade game. Because of the way an arcade monitor
works, the problem is nearly unnoticeable in the original game. I also checked if
the original PCB had the same “shadow effect” for the tiles:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border="0" />
        </p>
        <p>
As you can see, the hardware works that way:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border="0" />
          <br />
 <br />
Something curious about the protection... Javier told ElSemi that the protection of
this game took 8 months of work, so imagine how complicated it was… even the dallas
has some code that performs some pseudorandom dummy accesses to the shared RAM to
make black box attacks even more difficult.
</p>
        <p>
To clarify a question about the other protected games, having the World Rally dallas
code does not help to emulate the protection of them.  As MAME now has a DS5002FP
core and the other games are almost fully emulated, if we get the dallas code for
a game, it will be playable quickly.
</p>
        <p>
Finally, I want to thank to all the people that made this possible. It was cool to
be part of this. It has brought me some good memories and healed my wounds with Gaelco.
</p>
        <p>
          <strong>Update</strong>: <a href="http://www.gaelco.com">Gaelco</a> made public
the ROMs for World Rally. You can get them from <a href="http://www.gaelco.com">their
web page</a></p>
        <p>
For reference here are all the posts about World Rally emulation:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx">Part
1</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">Part
2</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">Part
3</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx">Part
4</a>
        </p>
        <p>
        </p>
        <p>
          <hr />
          <br />
La emulación del World Rally está completada. He implementado las prioridades (que
han sido más difíciles de lo que pensaba), los focos y sombras, y algún detalle que
faltaba del hardware gráfico. A continuación se muestran unas pantallas del driver: 
</p>
        <p>
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border="0" />
        </p>
        <p>
        </p>
        <p>
Es completamente  jugable sin que haya podido observar ningún problema. Pensé
que había algún fallo en la emulación del hardware gráfico cuando vi esto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border="0" />
        </p>
        <p>
Así que enchufé mi placa y la comparé al driver:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border="0" />
        </p>
        <p>
Como se observa, el problema también está presente en el juego original. Debido a
la forma en la que funciona un monitor de recreativa, el pequeño fallo gráfico es
prácticamente inapreciable en el juego original. También comprobé si el juego original
hacía el mismo “efecto de sombra” de los puentes:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border="0" />
        </p>
        <p>
Como se puede apreciar, el hardware funciona de esa manera:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border="0" />
        </p>
        <p>
Algo curioso sobre la protección… Javier le dijo a ElSemi que la desarrollar protección
del juego llevó 8 meses de trabajo. Inmaginad cómo de complicada es la protección…
Incluso el dallas tiene código para realizar accesos pseudoaleatorios a la memoria
compartido con el único motivo de hacer que los ataques de tipo caja negra sean incluso
más difíciles.
</p>
        <p>
Sobre la pregunta de si tener el código del dallas para el World Rally sirve para
emular la protección de los otros juegos, la respuesta es que no. Se necesita el código
de cada uno para hacerlo funcionar. Como ahora el MAME ya dispone de un emulador de
DS5002FP y los juegos de Gaelco protegidos están ya emulados completamente, una vez
que obtengamos el código del dallas para un juego, será jugable rápidamente.
</p>
        <p>
Por último, me gustaría darle las gracias a toda la gente que ha hecho esto posible.
Ha sido muy interesante poder formar parte de esto. Me ha traído muy gratos recuerdos
y ha cerrado viejas heridas con Gaelco.
</p>
        <p>
          <strong>Actualización</strong>: <a href="http://www.gaelco.com">Gaelco</a> ha
hecho públicas las ROMs del World Rally. Puedes obtenerlas desde <a href="http://www.gaelco.com">su
página web</a></p>
        <p>
A modo de referencia, aquí están todas las noticias sobre la emulación del World Rally:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx">Parte
1</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">Parte
2</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">Parte
3</a>
          <br />
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx">Parte
4</a>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=51ac1b35-5246-4e8c-9ee6-41334480a54e" />
      </body>
      <title>World Rally emulation completed</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</link>
      <pubDate>Mon, 12 May 2008 09:13:01 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
World Rally emulation is complete. I implemented priorities (that were trickier than
I thought), shadows/highlights and a few missing bits in the video hardware. Here
are some screenshots of the finished driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The game is fully playable from beginning to end without any problem as far as I can
tell. I thought there was a bug in the video hardware emulation somewhere when I saw
this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
So I plugged my PCB and compared it to the driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The problem is also in the original arcade game. Because of the way an arcade monitor
works, the problem is nearly unnoticeable in the original game. I also checked if
the original PCB had the same “shadow effect” for the tiles:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
As you can see, the hardware works that way:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border=0&gt;
&lt;br&gt;
&amp;nbsp;&lt;br&gt;
Something curious about the protection... Javier told ElSemi that the protection of
this game took 8 months of work, so imagine how complicated it was… even the dallas
has some code that performs some pseudorandom dummy accesses to the shared RAM to
make black box attacks even more difficult.
&lt;/p&gt;
&lt;p&gt;
To clarify a question about the other protected games, having the World Rally dallas
code does not help to emulate the protection of them.&amp;nbsp; As MAME now has a DS5002FP
core and the other games are almost fully emulated, if we get the dallas code for
a game, it will be playable quickly.
&lt;/p&gt;
&lt;p&gt;
Finally, I want to thank to all the people that made this possible. It was cool to
be part of this. It has brought me some good memories and healed my wounds with Gaelco.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href="http://www.gaelco.com"&gt;Gaelco&lt;/a&gt;&amp;nbsp;made public
the ROMs for World Rally. You can get them from &lt;a href="http://www.gaelco.com"&gt;their
web page&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
For reference here are all the posts about World Rally emulation:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx"&gt;Part
1&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;Part
2&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;Part
3&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;Part
4&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;br&gt;
La emulación del World Rally está completada. He implementado las prioridades (que
han sido más difíciles de lo que pensaba), los focos y sombras, y algún detalle que
faltaba del hardware gráfico. A continuación se muestran unas pantallas del driver: 
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic5.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic3.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic4.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic7.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrpic6.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Es completamente&amp;nbsp; jugable sin que haya podido observar ningún problema. Pensé
que había algún fallo en la emulación del hardware gráfico cuando vi esto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Así que enchufé mi placa y la comparé al driver:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic1.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Como se observa, el problema también está presente en el juego original. Debido a
la forma en la que funciona un monitor de recreativa, el pequeño fallo gráfico es
prácticamente inapreciable en el juego original. También comprobé si el juego original
hacía el mismo “efecto de sombra” de los puentes:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/gfx_problem2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Como se puede apreciar, el hardware funciona de esa manera:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/pcb_pic2.jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Algo curioso sobre la protección… Javier le dijo a ElSemi que la desarrollar protección
del juego llevó 8 meses de trabajo. Inmaginad cómo de complicada es la protección…
Incluso el dallas tiene código para realizar accesos pseudoaleatorios a la memoria
compartido con el único motivo de hacer que los ataques de tipo caja negra sean incluso
más difíciles.
&lt;/p&gt;
&lt;p&gt;
Sobre la pregunta de si tener el código del dallas para el World Rally sirve para
emular la protección de los otros juegos, la respuesta es que no. Se necesita el código
de cada uno para hacerlo funcionar. Como ahora el MAME ya dispone de un emulador de
DS5002FP y los juegos de Gaelco protegidos están ya emulados completamente, una vez
que obtengamos el código del dallas para un juego, será jugable rápidamente.
&lt;/p&gt;
&lt;p&gt;
Por último, me gustaría darle las gracias a toda la gente que ha hecho esto posible.
Ha sido muy interesante poder formar parte de esto. Me ha traído muy gratos recuerdos
y ha cerrado viejas heridas con Gaelco.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización&lt;/strong&gt;: &lt;a href="http://www.gaelco.com"&gt;Gaelco&lt;/a&gt;&amp;nbsp;ha
hecho públicas las ROMs del World Rally. Puedes obtenerlas desde &lt;a href="http://www.gaelco.com"&gt;su
página web&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
A modo de referencia, aquí están todas las noticias sobre la emulación del World Rally:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx"&gt;Parte
1&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;Parte
2&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;Parte
3&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;Parte
4&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=51ac1b35-5246-4e8c-9ee6-41334480a54e" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx</comments>
      <category>Games;MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=c7e7ab2e-fea4-4642-a9b7-e43a063662f1</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c7e7ab2e-fea4-4642-a9b7-e43a063662f1</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in english and then in spanish.<br />
Esta noticia está primero en inglés y luego en castellano.
</p>
        <p>
Javier sent us (via ElSemi) detailed information about how the encryption process
worked. However, he told us that the sheets of paper that contained the encryption
info were a bit difficult to read in some places (remember that this protection was
designed 15 years ago) so probably there was some mistakes in the excel file he sent
us. ElSemi and I tried to add it with the information he gave us but we didn’t have
success. <a href="http://mamelife.blogspot.com/">Nicola Salmoria</a> did an excellent
work (as always) consolidating the information and obtaining the missing information.
He generated a working decryption function that not only works for World Rally, but
also for Squash and Thunder Hoop.
</p>
        <p>
Mike Coates also completed the interface to get the data from a World Rally PCB, so
he was able to supply the encrypted/decrypted data that was needed to get the specific
details to decrypt World Rally properly.
</p>
        <p>
Special mention to <a href="http://andreasnaive.blogspot.com/">Andreas Naive</a> too.
The high level information Javier told us a few days ago was already discovered by
Andreas and posted in his page a couple of months ago. Before Javier sent us detailed
information about how the encryption worked I contacted Andreas Naive about the encryption
and he told me that he didn’t have free time at the moment to look at it. However
he told me an intuition he had about the algorithm:
</p>
        <p>
"I remember that my last feeling was that to decipher each 16 bits block, it was done
in 3 chunks: a first 6 bits chunk and then two 5 bits chunks, each of them based in
a/some bits of the first chunk. I don't remember exactly which ones, but the first
chunk was the one with a simple structure (based on the tables I published), while
the other two were the ones that shown a more complex structure (and carry effects)".<br />
He was completely right as that was how it worked the encryption that Javier sent
us.<br />
 <br />
It is good to have geniouses around ;-)
</p>
        <p>
After adding the decryption to the driver the game looks like this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border="0" />
        </p>
        <p>
It has a few graphic glitches that will be fixed soon but it seems to be PLAYABLE ;-)
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"><font color="#003399">here</font></a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Javier nos ha mandado (via ElSemi) información detallada sobre cómo funciona el proceso
de encriptación. Sin embargo, las hojas donde tenía detallado el funcionamiento del
algoritmo eran difíciles de leer en algunos sitios (ya que la protección fue diseñada
hace 15 años) por lo que probablemente habría alguna errata en el fichero Excel que
nos mandó.  ElSemi y yo intentamos en vano añadir la información de Javier. <a href="http://mamelife.blogspot.com/">Nicola
Salmoria</a> ha realizado un trabajo excelente (como siempre) terminando de pulir
esa información y descubrir los detalles que faltaban. El ha implementado una función
de desencriptación que funciona no solo para el World Rally, sino también para el
Squash y el Thunder Hoop.
</p>
        <p>
Mike Coates terminó el interfaz para obtener datos de la placa del World Rally, suministrando
valores encriptados y sus correspondientes valores desencriptados, que permitieron
obtener los datos específicos necesarios para la correcta desencriptación del World
Rally.
</p>
        <p>
Mención especial a <a href="http://andreasnaive.blogspot.com/">Andreas Naive</a>.
La información de alto nivel que Javier nos dio hace unos días ya había sido descubierta
por Andreas, que la publicó en su página hace unos meses. Antes de que Javier nos
diera la información detallada sobre cómo funcionaba la encriptación, contacté con
Andreas Naive sobre el tema. Me dijo que ahora mismo no tenía tiempo disponible para
mirarlo. Sin embargo, me dijo que tenía un pálpito:
</p>
        <p>
“Al descifrar cada bloque de 16 bits, se hacía en tres trozos: un primer bloque de
6 bits y luego dos bloques de 5 bits, cada uno de ellos basados en un/unos bits del
primer bloque. No recuerdo cuáles eran cuáles, pero el primer bloque era el que tenía
una estructura más sencilla (según las tablas que publiqué), mientras que los otros
dos son los que mostraban estructura más compleja (y efectos de acarreo debidos a
alguna suma).”
</p>
        <p>
El algoritmo que nos había mandado Javier funciona exactamente de esa forma.
</p>
        <p>
Está bien estar rodeado de genios ;-)
</p>
        <p>
Después de añadir el algoritmo para desencriptar los datos, el juego mostraba este
aspecto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border="0" />
        </p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border="0" />
        </p>
        <p>
El juego tiene algunos fallos gráficos que se corregirán pronto pero es JUGABLE (lo
poco que he probado) ;-)
</p>
        <p>
          <strong>Update:</strong> se ha completado la emulación del World Rally. Puedes
leer sobre ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"><font color="#003399">aquí</font></a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c7e7ab2e-fea4-4642-a9b7-e43a063662f1" />
      </body>
      <title>Playable status reached</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</link>
      <pubDate>Sat, 10 May 2008 18:52:23 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in english and then in spanish.&lt;br&gt;
Esta noticia está primero en inglés&amp;nbsp;y luego en castellano.
&lt;/p&gt;
&lt;p&gt;
Javier sent us (via ElSemi) detailed information about how the encryption process
worked. However, he told us that the sheets of paper that contained the encryption
info were a bit difficult to read in some places (remember that this protection was
designed 15 years ago) so probably there was some mistakes in the excel file he sent
us. ElSemi and I tried to add it with the information he gave us but we didn’t have
success. &lt;a href="http://mamelife.blogspot.com/"&gt;Nicola Salmoria&lt;/a&gt; did an excellent
work (as always) consolidating the information&amp;nbsp;and obtaining the missing information.
He generated a working decryption function that not only works for World Rally, but
also for Squash and Thunder Hoop.
&lt;/p&gt;
&lt;p&gt;
Mike Coates also completed the interface to get the data from a World Rally PCB, so
he was able to supply the encrypted/decrypted data that was needed to get the specific
details to decrypt World Rally properly.
&lt;/p&gt;
&lt;p&gt;
Special mention to&amp;nbsp;&lt;a href="http://andreasnaive.blogspot.com/"&gt;Andreas Naive&lt;/a&gt;&amp;nbsp;too.
The high level information Javier told us a few days ago was already discovered by
Andreas and posted in his page a couple of months ago. Before Javier sent us detailed
information about how the encryption worked I contacted Andreas Naive about the encryption
and he told me that he didn’t have free time at the moment to look at it. However
he told me an intuition he had about the algorithm:
&lt;/p&gt;
&lt;p&gt;
"I remember that my last feeling was that to decipher each 16 bits block, it was done
in 3 chunks: a first 6 bits chunk and then two 5 bits chunks, each of them based in
a/some bits of the first chunk. I don't remember exactly which ones, but the first
chunk was the one with a simple structure (based on the tables I published), while
the other two were the ones that shown a more complex structure (and carry effects)".&lt;br&gt;
He was completely right as that was how it worked the encryption that Javier sent
us.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
It is good to have geniouses around ;-)
&lt;/p&gt;
&lt;p&gt;
After adding the decryption to the driver the game looks like this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
It has a few graphic glitches that will be fixed soon but it seems to be PLAYABLE&amp;nbsp;;-)
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;&lt;font color=#003399&gt;here&lt;/font&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Javier nos ha mandado (via ElSemi) información detallada sobre cómo funciona el proceso
de encriptación. Sin embargo, las hojas donde tenía detallado el funcionamiento del
algoritmo eran difíciles de leer en algunos sitios (ya que la protección fue diseñada
hace 15 años) por lo que probablemente habría alguna errata en el fichero Excel que
nos mandó.&amp;nbsp; ElSemi y yo intentamos en vano añadir la información de Javier. &lt;a href="http://mamelife.blogspot.com/"&gt;Nicola
Salmoria&lt;/a&gt; ha realizado un trabajo excelente (como siempre) terminando de pulir
esa información y descubrir los detalles que faltaban. El ha implementado una función
de desencriptación que funciona no solo para el World Rally, sino también para el
Squash y el Thunder Hoop.
&lt;/p&gt;
&lt;p&gt;
Mike Coates terminó el interfaz para obtener datos de la placa del World Rally, suministrando
valores encriptados y sus correspondientes valores desencriptados, que permitieron
obtener los datos específicos necesarios para la correcta desencriptación del World
Rally.
&lt;/p&gt;
&lt;p&gt;
Mención especial a&amp;nbsp;&lt;a href="http://andreasnaive.blogspot.com/"&gt;Andreas Naive&lt;/a&gt;.
La información de alto nivel que Javier nos dio hace unos días ya había sido descubierta
por Andreas, que la publicó en su página hace unos meses. Antes de que Javier nos
diera la información detallada sobre cómo funcionaba la encriptación, contacté con
Andreas Naive sobre el tema. Me dijo que ahora mismo no tenía tiempo disponible para
mirarlo. Sin embargo, me dijo que tenía un pálpito:
&lt;/p&gt;
&lt;p&gt;
“Al descifrar cada bloque de 16 bits, se hacía en tres trozos: un primer bloque de
6 bits y luego dos bloques de 5 bits, cada uno de ellos basados en un/unos bits del
primer bloque. No recuerdo cuáles eran cuáles, pero el primer bloque era el que tenía
una estructura más sencilla (según las tablas que publiqué), mientras que los otros
dos son los que mostraban estructura más compleja (y efectos de acarreo debidos a
alguna suma).”
&lt;/p&gt;
&lt;p&gt;
El algoritmo que nos había mandado Javier funciona exactamente de esa forma.
&lt;/p&gt;
&lt;p&gt;
Está bien estar rodeado de genios ;-)
&lt;/p&gt;
&lt;p&gt;
Después de añadir el algoritmo para desencriptar los datos, el juego mostraba este
aspecto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0000.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0001.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0002.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0003.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/0005.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
El juego tiene algunos fallos gráficos que se corregirán pronto pero es JUGABLE (lo
poco que he probado) ;-)
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; se ha completado la emulación del World Rally.&amp;nbsp;Puedes
leer sobre ello&amp;nbsp;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,51ac1b35-5246-4e8c-9ee6-41334480a54e.aspx"&gt;&lt;font color=#003399&gt;aquí&lt;/font&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c7e7ab2e-fea4-4642-a9b7-e43a063662f1" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx</comments>
      <category>Games;MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
The Dallas DS5002FP core is complete. The additions to the 8051 core are:
</p>
        <p>
- Extra Special Function Registers<br />
- Byte-wide Bus Support<br />
- Memory Partition and Memory Range<br />
- Bootstrap Configuration<br />
- Power Fail Interrupt<br />
- Timed Access<br />
- Stop Mode<br />
- Idle Mode
</p>
        <p>
I didn’t bother to add support for Peripherals, the Reprogrammable Peripheral Controller
or CRC-16 support because it isn’t used by the game.
</p>
        <p>
The communication between the Dallas and the main CPU seems to be working, however,
the game writes some bytes to the encrypted Video RAM, it reads them back and then
makes some calls based on the decrypted data. As the current decryption is wrong,
the game doesn’t work yet and never uses the dallas for anything interesting right
now.
</p>
        <p>
The decryption of the Video RAM is in the same state as it was. However, ElSemi asked
Javier for information about the decryption and he is trying to help us. He didn’t
remember how it was performed but we send him the information we got about it in 2002
(when Mike connected the PCB to the fluke) to refresh a bit his memory. Thanks to
that, he gave us another point of view about how the encryption may work. Even if
he is right, we still need to get data from the original PCB. Hopefully, somewhere
in the process we end up with a clean decrypt function that uses no tables.
</p>
        <p>
Understanding some code I was able to guess some decrypted values and get this:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
It looks really ugly as the colors for the tiles aren’t decrypted properly but this
finally confirms that World Rally uses the same Video Hardware as Target Hits. The
only change seems to be the additional palette entries for the night races. I have
seen how the palette was configured in a night race and I have an idea of how the
palette works for the night races (not very different from World Rally 2), but we’ll
have to wait until the game works to implement it.
</p>
        <p>
So, the current status is that if the Video RAM is decrypted properly and we are lucky,
the game should work without the light effects (and maybe some priority problems)
and be playable. If we are not that lucky, hopefully the problems are not difficult
to find and fix.
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">here</a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
El emulador del Dallas DS5002FP está completado. Lo que se ha añadido al emulador
del 8051es:
</p>
        <p>
- Registros de funciones especiales (SFRs) extra<br />
- Soporte del Byte-wide bus<br />
- Partición y Rango de memoria<br />
- Configuration de arranque<br />
- Interrupción por falta de energía<br />
- Acceso temporizado<br />
- Modo Stop<br />
- Modo Idle
</p>
        <p>
No he añadido soporte de periféricos ni el Controlador Reprogramable de Periféricos,
porque no son usados por el juego.
</p>
        <p>
La comunicación entre el Dallas y la CPU principal parece estar funcionando correctamente.
Sin embargo, el juego escribe algunos bytes a la memoria de Video encriptada, luego
los lee desencriptados y hace unos saltos dependiendo del valor desencriptado. Como
la desencriptación actual es incorrecta, el juego sigue sin funcionar todavía y no
utiliza el dallas para nada interesante todavía.
</p>
        <p>
La desencriptación de la memoria de Video sigue igual. Sin embargo, ElSemi le ha pedido
a Javier información sobre la encriptación y nos está tratando de ayudar. Javier no
recordaba cómo funcionaba la encriptación por lo que le hemos mandado la información
que obtuvimos en 2002 (cuando Mike conectó la placa al fluke) para refrescar su memoria.
Gracias a ello, Javier nos ha dado otro punto de vista de cómo podría funcionar la
encriptación. Aún si está en lo cierto, con lo que nos ha dicho aún necesitamos obtener
datos de la placa original. Con un poco de suerte, en algún momento terminaremos con
una función de desencriptación clara que no usa tablas.
</p>
        <p>
Entendiendo un poco de código he podido intuir unos cuantos valores desencriptados
y obtener esto:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border="0" />
        </p>
        <p>
 
</p>
        <p>
Se ve realmente feo porque los colores de los bloques no están desencriptados correctamente
pero esto confirma finalmente que el World Rally utiliza el mismo hardware gráfico
que el Target Hits. El único cambio son unas entradas adicionales de la paleta para
las carreras nocturnas. He podido ver como se configuraba la paleta en una carrera
nocturna y tengo una idea de cómo va (parecido al World Rally 2), pero habrá
que esperar a que el juego funcione para poder implementarlo.
</p>
        <p>
Por lo tanto, el estado actual es que si la RAM de Video se desencripta correctamente
y tenemos un poco de suerte, el juego debería funcionar sin los efectos de luz (y
quizás con algún problema de prioridades), pero sería jugable. Si no somos tan afortunados,
con un poco más de trabajo encontraremos y arreglaremos los problemas que surjan.
</p>
        <p>
          <strong>Actualización:</strong> se ha avanzado un poco más. Puedes leer sobre
ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx">aquí</a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9" />
      </body>
      <title>More World Rally news</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</link>
      <pubDate>Wed, 07 May 2008 06:18:05 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
The Dallas DS5002FP core is complete. The additions to the 8051 core are:
&lt;/p&gt;
&lt;p&gt;
- Extra Special Function Registers&lt;br&gt;
- Byte-wide Bus Support&lt;br&gt;
- Memory Partition and Memory Range&lt;br&gt;
- Bootstrap Configuration&lt;br&gt;
- Power Fail Interrupt&lt;br&gt;
- Timed Access&lt;br&gt;
- Stop Mode&lt;br&gt;
- Idle Mode
&lt;/p&gt;
&lt;p&gt;
I didn’t bother to add support for Peripherals, the Reprogrammable Peripheral Controller
or CRC-16 support because it isn’t used by the game.
&lt;/p&gt;
&lt;p&gt;
The communication between the Dallas and the main CPU seems to be working, however,
the game writes some bytes to the encrypted Video RAM, it reads them back and then
makes some calls based on the decrypted data. As the current decryption is wrong,
the game doesn’t work yet and never uses the dallas for anything interesting right
now.
&lt;/p&gt;
&lt;p&gt;
The decryption of the Video RAM is in the same state as it was. However, ElSemi asked
Javier for information about the decryption and he is trying to help us. He didn’t
remember how it was performed but we send him the information we got about it in 2002
(when Mike connected the PCB to the fluke) to refresh a bit his memory. Thanks to
that, he gave us another point of view about how the encryption may work. Even if
he is right, we still need to get data from the original PCB. Hopefully, somewhere
in the process we end up with a clean decrypt function that uses no tables.
&lt;/p&gt;
&lt;p&gt;
Understanding some code I was able to guess some decrypted values and get this:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
It looks really ugly as the colors for the tiles aren’t decrypted properly but this
finally confirms that World Rally uses the same Video Hardware as Target Hits. The
only change seems to be the additional palette entries for the night races. I have
seen how the palette was configured in a night race and I have an idea of how the
palette works for the night races (not very different from World Rally 2), but we’ll
have to wait until the game works to implement it.
&lt;/p&gt;
&lt;p&gt;
So, the current status is that if the Video RAM is decrypted properly and we are lucky,
the game should work without the light effects (and maybe some priority problems)
and be playable. If we are not that lucky, hopefully the problems are not difficult
to find and fix.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
El emulador del Dallas DS5002FP está completado. Lo que se ha añadido al emulador
del 8051es:
&lt;/p&gt;
&lt;p&gt;
- Registros de funciones especiales (SFRs) extra&lt;br&gt;
- Soporte del Byte-wide bus&lt;br&gt;
- Partición y Rango de memoria&lt;br&gt;
- Configuration de arranque&lt;br&gt;
- Interrupción por falta de energía&lt;br&gt;
- Acceso temporizado&lt;br&gt;
- Modo Stop&lt;br&gt;
- Modo Idle
&lt;/p&gt;
&lt;p&gt;
No he añadido soporte de periféricos ni el Controlador Reprogramable de Periféricos,
porque no son usados por el juego.
&lt;/p&gt;
&lt;p&gt;
La comunicación entre el Dallas y la CPU principal parece estar funcionando correctamente.
Sin embargo, el juego escribe algunos bytes a la memoria de Video encriptada, luego
los lee desencriptados y hace unos saltos dependiendo del valor desencriptado. Como
la desencriptación actual es incorrecta, el juego sigue sin funcionar todavía y no
utiliza el dallas para nada interesante todavía.
&lt;/p&gt;
&lt;p&gt;
La desencriptación de la memoria de Video sigue igual. Sin embargo, ElSemi le ha pedido
a Javier información sobre la encriptación y nos está tratando de ayudar. Javier no
recordaba cómo funcionaba la encriptación por lo que le hemos mandado la información
que obtuvimos en 2002 (cuando Mike conectó la placa al fluke) para refrescar su memoria.
Gracias a ello, Javier nos ha dado otro punto de vista de cómo podría funcionar la
encriptación. Aún si está en lo cierto, con lo que nos ha dicho aún necesitamos obtener
datos de la placa original. Con un poco de suerte, en algún momento terminaremos con
una función de desencriptación clara que no usa tablas.
&lt;/p&gt;
&lt;p&gt;
Entendiendo un poco de código he podido intuir unos cuantos valores desencriptados
y obtener esto:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrallypres.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Se ve realmente feo porque los colores de los bloques no están desencriptados correctamente
pero esto confirma finalmente que el World Rally utiliza el mismo hardware gráfico
que el Target Hits. El único cambio son unas entradas adicionales de la paleta para
las carreras nocturnas. He podido ver como se configuraba la paleta en una carrera
nocturna y tengo una idea de cómo&amp;nbsp;va (parecido al World Rally 2), pero habrá
que esperar a que el juego funcione para poder implementarlo.
&lt;/p&gt;
&lt;p&gt;
Por lo tanto, el estado actual es que si la RAM de Video se desencripta correctamente
y tenemos un poco de suerte, el juego debería funcionar sin los efectos de luz (y
quizás con algún problema de prioridades), pero sería jugable. Si no somos tan afortunados,
con un poco más de trabajo&amp;nbsp;encontraremos y arreglaremos los problemas que surjan.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización:&lt;/strong&gt; se ha avanzado un poco más.&amp;nbsp;Puedes leer sobre
ello &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,c7e7ab2e-fea4-4642-a9b7-e43a063662f1.aspx"&gt;aquí&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=6aff4d5b-3e22-4a5d-af35-22dc8293e2f9" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx</comments>
      <category>Games;MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5</wfw:commentRss>
      <slash:comments>19</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in English and then in Spanish<br />
Esta noticia está primero en inglés y luego en español
</p>
        <p>
If you have tried to execute World Rally since it was added to MAME you have seen
the precarious state of the driver. The protection of World Rally is double:
</p>
        <p>
          <strong>Encrypted Video RAM:</strong>
        </p>
        <p>
The encrypted Video RAM transforms a 32 bits value written to it to another value
that is really complex to derive from the original value. This protection was also
used in Thunder Hoop and Squash. Mike Coates connected a fluke to his PCBs and got
a 4 GB file will all possible combinations (2^32) for Thunder Hoop and Squash. 
Using that file, the encryption process was replicated.  However, it was not
very practical to require a 16 GB file to run the game. Nicola Salmoria studied
the file and generated some code (about 400 lines) that replicated the original encryption.
That’s why you can play Thunder Hoop and Squash.
</p>
        <p>
Why World Rally encryption is incomplete? All of us wanted to see World Rally running
before any other game, so we started studying World Rally before Squash and Thunder
Hoop. In that time, we thought that the encryption was only performed in 16 bits,
not 32. Unfortunately, when Mike got all decrypted values (2^16), the code was clearly
showing that the decrypted values were not correct in most cases (for example, one
of the methods that draws the tiles uses a decrypted value for the number of tiles
to draw. That’s why the power on self test results and other screens look horrible
right now).  After we find that out, the decryption efforts were centered in
the other games. As World Rally was not going to be playable unless the dallas code
was dumped (something that seemed unlikely), it has remained that way.
</p>
        <p>
          <strong>Dallas DS5002FP secure MCU:</strong>
        </p>
        <p>
The Dallas MCU in the Gaelco games has some critical code that handles inputs, objects
manipulation and other complex calculations that prevent the game from working properly
(Take a look at World Rally 2 if you don’t know what I mean). The DS5002FP MCU has
been one of the best chips for protecting information on its era making emulation
of these games impossible for now. There are some specialized labs that claim to be
able to get the code from a DS5002FP but it is an incredibly expensive process we
can’t afford.
</p>
        <p>
I have to admit that I thought that I’d never see World Rally emulated, as I approached
some people at Gaelco and Zigurat for the Dallas code without luck. However, the other
day I received an email that changed my mind. Miguel Angel Horna (ElSemi) did a talk
at Lleida Lan Party about emulation. At the party he met one of the Gaelco founders
(Javier Valero) that was there to speak about the arcade game industry. ElSemi and
Javier talked about the protection in some Gaelco games and Javier was kind enough
to provide the dallas code for World Rally. With the internal code of the DS5002FP
it is just a matter of time to finally have a working driver in MAME.
</p>
        <p>
I have been completely inactive from <a href="http://mamedev.org/">MAME</a> development
for a while but as I worked on the drivers of all the Gaelco 2D games (except Master
Boy) and I spent a lot of time and money on them, I thought it was a good time to
resume my work on MAME. 
</p>
        <p>
Mike Coates is trying to get all the possible values from World Rally Video RAM so
we can advance in that area too.
</p>
        <p>
Currently I am writing a DS5002FP core to run the dallas code. The DS5002FP is just
a 8051 MCU with some additions and as MAME already has a 8051 core things are going
fast. For example, the initial coprocessor test works (although it is a trivial test
to pass without the dallas code):
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border="0" />
        </p>
        <p>
Also, adding the Power Fail Interrupt of the dallas I managed to see this screen that
is supposed to be seen when the dallas is dying:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border="0" />
        </p>
        <p>
After the both protections are emulated the driver will need more work as probably
the video hardware emulation isn’t complete and needs some tweaks here and there but
I’m confident that World Rally will be playable in a not so distant future. I don’t
know if Javier will give us more dallas code or not, but hats off to him for this
one. Also, thanks a lot to ElSemi for being able to get the dallas code from him.
</p>
        <p>
          <strong>Update:</strong> more progress has been made. You can read about it <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">here</a></p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Si has tratado de ejecutar el World Rally desde que fue añadido al MAME habrás visto
el estado tan precario del driver. La protección del World Rally es doble:
</p>
        <p>
          <strong>Memoria de Video Encriptada:</strong>
        </p>
        <p>
La memoria de video encriptada transforma los valores de 32 bits que se escriben en
ella, de forma que el valor resultante es extremadamente difícil de obtenerlo dado
el valor original. Esta protección también se utilizó en el Thunder Hoop y en el Squash.
Mike Coates conecto un fluke a su placa y obtuvo un archivo de 4 GB con todas las
combinaciones posibles (2^32). Usando ese archivo, se pudo replicar la encriptación.
Sin embargo, no era muy práctico necesitar un archivo de 16 GB para ejecutar
el juego. Nicola Salmoria estudió el archivo y obtuvo un código (cerca de 400 líneas)
que obtenía los mismos valores de la encriptación. Por ello se puede jugar al Thunder
Hoop y al Squash actualmente.
</p>
        <p>
¿Por qué la encriptación del World Rally está incompleta? Todos queríamos ver el World
Rally funcionando antes que cualquier otro juego, por lo que empezamos a estudiar
el World Rally antes que el Squash y el Thunder Hoop. En esa época, pensábamos que
la encriptación solo era de 16 bits, no de 32. Cuando Mike obtuvo los valores desencriptados
(2^16) pudimos comprobar la cruda realidad. El código mostraba claramente que los
valores desencriptados no eran correctos en la mayoría de los casos (por ejemplo,
uno de los métodos que dibuja los fondos de las pantallas usa un valor desencriptado
como el número de bloques a dibujar. Por eso la carta de ajuste inicial que muestra
los resultados de los tests iniciales se ve tan mal actualmente). Después de percatarnos
de nuestro error, los esfuerzos se centraron en el resto de juegos. Como el World
Rally no iba a ser jugable a no ser que el código del dallas se obtuviera  (cosa
que parecía altamente improbable), se ha mantenido como estaba.
</p>
        <p>
          <strong>Microcontrollador Dallas DS5002FP:</strong>
        </p>
        <p>
El Microcontrolador Dallas en los juegos de Gaelco contiene código crítico que maneja
la entradas de los jugadores, la manipulación de objetos u otros cálculos complejos
que hacen que los juegos no funcionen correctamente (prueba el World Rally 2 si no
sabes a lo que me refiero). El DS5002FP ha sido uno de los chips con más éxito a la
hora de proteger información en su época, haciendo que la emulación de estos juegos
fuera imposible. Hay laboratorios especializados que presumen de poder obtener el
código de un DS5002FP pero es un proceso increíblemente caro que no nos podemos permitir.
</p>
        <p>
Debo admitir que pensé que nunca vería el Word Rally emulado, ya que contacté con
varias personas de Gaelco y Zigurat preguntando por el código del Dallas pero no hubo
suerte en ese momento. Sin embargo, el otro día recibí un email que me hizo cambiar
de opinión. Miguel Angel Horna (ElSemi) dio una charla en la Lleida Lan Party sobre
emulación. En la party conoció a uno de los fundadores de Gaelco (Javier Valero) que
estaba allí para hablar acerca de la industria de los juegos recreativos. ElSemi y
Javier hablaron sobre la protección en algunos juegos de Gaelco y Javier tuvo el detalle
de dar el código del dallas que usa el World Rally. Con el código interno del DS5002FP
es sólo una cuestión de tiempo de que finalmente el juego pueda funcionar correctamente
en el MAME.
</p>
        <p>
He estado completamente inactivo en el desarrollo de cosas para el <a href="http://mamedev.org/">MAME</a> bastante
tiempo, pero como trabajé en los drivers de todos los juegos 2D de Gaelco (excepto
el Master Boy) y me he dejado un montón de tiempo y dinero en ellos, he pensado que
sería un buen momento para trabajar un poco más en el MAME.
</p>
        <p>
Mike Coates está tratando de obtener los posibles valores de la memoria encriptada
del World Rally para ir avanzando en ese aspecto.
</p>
        <p>
Por mi parte, estoy escribiendo un core para el procesador DS5002FP de forma que se
pueda ejecutar el código del dallas en MAME. El DS5002FP es un microcontrolador 8051
con ligeros cambios, y como ya hay un core del 8051 en MAME, la cosa avanza rápido.
Por ejemplo, las comprobaciones iniciales del coprocesador funcionan (aunque es un
test tan sencillo, que se puede parchear sin tener el código del dallas, pero bueno):
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border="0" />
        </p>
        <p>
Emulando la interrupción de fallo de tension del dallas, he conseguido ver esta pantalla
que se muestra cuando se le acaba la pila al dallas y su contenido deja de funcionar:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border="0" />
        </p>
        <p>
Después de que ámbas protecciones hayan sido emuladas el driver necesitara un poco
más de trabajo porque probablemente la emulación de video requiera unas mejoras pero
estoy convencido de que el World Rally será jugable en un futuro no muy lejano. No
se si Javier nos pasará más códigos del dallas para otros juegos o no, pero me quito
el sombrero por lo que ya nos ha dado. Muchísimas gracias a ElSemi por conseguir el
código del Dallas.
</p>
        <p>
          <strong>Actualización:</strong> se ha avanzado un poco más. Puedes leer sobre
ello <a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx">aquí</a></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5" />
      </body>
      <title>World Rally, finally</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</link>
      <pubDate>Mon, 05 May 2008 19:19:39 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in English and then in Spanish&lt;br&gt;
Esta noticia está primero en inglés y luego en español
&lt;/p&gt;
&lt;p&gt;
If you have tried to execute World Rally since it was added to MAME you have seen
the precarious state of the driver. The protection of World Rally is double:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Encrypted Video RAM:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The encrypted Video RAM transforms a 32 bits value written to it to another value
that is really complex to derive from the original value. This protection was also
used in Thunder Hoop and Squash. Mike Coates connected a fluke to his PCBs and got
a 4 GB file will all possible combinations (2^32) for Thunder Hoop and Squash.&amp;nbsp;
Using that file, the encryption process was replicated.&amp;nbsp; However, it was not
very practical to require a&amp;nbsp;16 GB file to run the game. Nicola Salmoria studied
the file and generated some code (about 400 lines) that replicated the original encryption.
That’s why you can play Thunder Hoop and Squash.
&lt;/p&gt;
&lt;p&gt;
Why World Rally encryption is incomplete? All of us wanted to see World Rally running
before any other game, so we started studying World Rally before Squash and Thunder
Hoop. In that time, we thought that the encryption was only performed in 16 bits,
not 32. Unfortunately, when Mike got all decrypted values (2^16), the code was clearly
showing that the decrypted values were not correct in most cases (for example, one
of the methods that draws the tiles uses a decrypted value for the number of tiles
to draw. That’s why the power on self test results and other screens look horrible
right now).&amp;nbsp; After we find that out, the decryption efforts were centered in
the other games. As World Rally was not going to be playable unless the dallas code
was dumped (something that seemed unlikely), it has remained that way.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Dallas DS5002FP secure MCU:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The Dallas MCU in the Gaelco games has some critical code that handles inputs, objects
manipulation and other complex calculations that prevent the game from working properly
(Take a look at World Rally 2 if you don’t know what I mean). The DS5002FP MCU has
been one of the best chips for protecting information on its era making emulation
of these games impossible for now. There are some specialized labs that claim to be
able to get the code from a DS5002FP but it is an incredibly expensive process we
can’t afford.
&lt;/p&gt;
&lt;p&gt;
I have to admit that I thought that I’d never see World Rally emulated, as I approached
some people at Gaelco and Zigurat for the Dallas code without luck. However, the other
day I received an email that changed my mind. Miguel Angel Horna (ElSemi) did a talk
at Lleida Lan Party about emulation. At the party he met one of the Gaelco founders
(Javier Valero) that was there to speak about the arcade game industry. ElSemi and
Javier talked about the protection in some Gaelco games and Javier was kind enough
to provide the dallas code for World Rally. With the internal code of the DS5002FP
it is just a matter of time to finally have a working driver in MAME.
&lt;/p&gt;
&lt;p&gt;
I have been completely inactive from &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt; development
for a while but as I worked on the drivers of all the Gaelco 2D games (except Master
Boy) and I spent a lot of time and money on them, I thought it was a good time to
resume my work on MAME. 
&lt;/p&gt;
&lt;p&gt;
Mike Coates is trying to get all the possible values from World Rally Video RAM so
we can advance in that area too.
&lt;/p&gt;
&lt;p&gt;
Currently I am writing a DS5002FP core to run the dallas code. The DS5002FP is just
a 8051 MCU with some additions and as MAME already has a 8051 core things are going
fast. For example, the initial coprocessor test works (although it is a trivial test
to pass without the dallas code):
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Also, adding the Power Fail Interrupt of the dallas I managed to see this screen that
is supposed to be seen when the dallas is dying:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
After the both protections are emulated the driver will need more work as probably
the video hardware emulation isn’t complete and needs some tweaks here and there but
I’m confident that World Rally will be playable in a not so distant future. I don’t
know if Javier will give us more dallas code or not, but hats off to him for this
one. Also, thanks a lot to ElSemi for being able to get the dallas code from him.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update:&lt;/strong&gt; more progress has been made. You can read about it &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;here&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Si has tratado de ejecutar el World Rally desde que fue añadido al MAME habrás visto
el estado tan precario del driver. La protección del World Rally es doble:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Memoria de Video Encriptada:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
La memoria de video encriptada transforma los valores de 32 bits que se escriben en
ella, de forma que el valor resultante es extremadamente difícil de obtenerlo dado
el valor original. Esta protección también se utilizó en el Thunder Hoop y en el Squash.
Mike Coates conecto un fluke a su placa y obtuvo un archivo de 4 GB con todas las
combinaciones posibles (2^32). Usando ese archivo, se pudo replicar la encriptación.
Sin embargo, no era muy práctico necesitar un archivo de&amp;nbsp;16 GB para ejecutar
el juego. Nicola Salmoria estudió el archivo y obtuvo un código (cerca de 400 líneas)
que obtenía los mismos valores de la encriptación. Por ello se puede jugar al Thunder
Hoop y al Squash actualmente.
&lt;/p&gt;
&lt;p&gt;
¿Por qué la encriptación del World Rally está incompleta? Todos queríamos ver el World
Rally funcionando antes que cualquier otro juego, por lo que empezamos a estudiar
el World Rally antes que el Squash y el Thunder Hoop. En esa época, pensábamos que
la encriptación solo era de 16 bits, no de 32. Cuando Mike obtuvo los valores desencriptados
(2^16) pudimos comprobar la cruda realidad. El código mostraba claramente que los
valores desencriptados no eran correctos en la mayoría de los casos (por ejemplo,
uno de los métodos que dibuja los fondos de las pantallas usa un valor desencriptado
como el número de bloques a dibujar. Por eso la carta de ajuste inicial que muestra
los resultados de los tests iniciales se ve tan mal actualmente). Después de percatarnos
de nuestro error, los esfuerzos se centraron en el resto de juegos. Como el World
Rally no iba a ser jugable a no ser que el código del dallas se obtuviera&amp;nbsp; (cosa
que parecía altamente improbable), se ha mantenido como estaba.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Microcontrollador Dallas DS5002FP:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
El Microcontrolador Dallas en los juegos de Gaelco contiene código crítico que maneja
la entradas de los jugadores, la manipulación de objetos u otros cálculos complejos
que hacen que los juegos no funcionen correctamente (prueba el World Rally 2 si no
sabes a lo que me refiero). El DS5002FP ha sido uno de los chips con más éxito a la
hora de proteger información en su época, haciendo que la emulación de estos juegos
fuera imposible. Hay laboratorios especializados que presumen de poder obtener el
código de un DS5002FP pero es un proceso increíblemente caro que no nos podemos permitir.
&lt;/p&gt;
&lt;p&gt;
Debo admitir que pensé que nunca vería el Word Rally emulado, ya que contacté con
varias personas de Gaelco y Zigurat preguntando por el código del Dallas pero no hubo
suerte en ese momento. Sin embargo, el otro día recibí un email que me hizo cambiar
de opinión. Miguel Angel Horna (ElSemi) dio una charla en la Lleida Lan Party sobre
emulación. En la party conoció a uno de los fundadores de Gaelco (Javier Valero) que
estaba allí para hablar acerca de la industria de los juegos recreativos. ElSemi y
Javier hablaron sobre la protección en algunos juegos de Gaelco y Javier tuvo el detalle
de dar el código del dallas que usa el World Rally. Con el código interno del DS5002FP
es sólo una cuestión de tiempo de que finalmente el juego pueda funcionar correctamente
en el MAME.
&lt;/p&gt;
&lt;p&gt;
He estado completamente inactivo en el desarrollo de cosas para el &lt;a href="http://mamedev.org/"&gt;MAME&lt;/a&gt; bastante
tiempo, pero como trabajé en los drivers de todos los juegos 2D de Gaelco (excepto
el Master Boy) y me he dejado un montón de tiempo y dinero en ellos, he pensado que
sería un buen momento para trabajar un poco más en el MAME.
&lt;/p&gt;
&lt;p&gt;
Mike Coates está tratando de obtener los posibles valores de la memoria encriptada
del World Rally para ir avanzando en ese aspecto.
&lt;/p&gt;
&lt;p&gt;
Por mi parte, estoy escribiendo un core para el procesador DS5002FP de forma que se
pueda ejecutar el código del dallas en MAME. El DS5002FP es un microcontrolador 8051
con ligeros cambios, y como ya hay un core del 8051 en MAME, la cosa avanza rápido.
Por ejemplo, las comprobaciones iniciales del coprocesador funcionan (aunque es un
test tan sencillo, que se puede parchear sin tener el código del dallas, pero bueno):
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Emulando la interrupción de fallo de tension del dallas, he conseguido ver esta pantalla
que se muestra cuando se le acaba la pila al dallas y su contenido deja de funcionar:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/wrally2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Después de que ámbas protecciones hayan sido emuladas el driver necesitara un poco
más de trabajo porque probablemente la emulación de video requiera unas mejoras pero
estoy convencido de que el World Rally será jugable en un futuro no muy lejano. No
se si Javier nos pasará más códigos del dallas para otros juegos o no, pero me quito
el sombrero por lo que ya nos ha dado. Muchísimas gracias a ElSemi por conseguir el
código del Dallas.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Actualización:&lt;/strong&gt; se ha avanzado un poco más.&amp;nbsp;Puedes leer sobre
ello&amp;nbsp;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,6aff4d5b-3e22-4a5d-af35-22dc8293e2f9.aspx"&gt;aquí&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=c20ef5fd-9018-4b83-bba6-63ce3edb5ba5" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,c20ef5fd-9018-4b83-bba6-63ce3edb5ba5.aspx</comments>
      <category>Games;MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=a44d4086-0b51-4a94-93c0-313f51ecb86e</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,a44d4086-0b51-4a94-93c0-313f51ecb86e.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,a44d4086-0b51-4a94-93c0-313f51ecb86e.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a44d4086-0b51-4a94-93c0-313f51ecb86e</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Nicola Salmoria was able to decrypt a complete CPS2 game algorithmically without using
any table!
</p>
        <p>
Well, to be fair Andreas Naive played a key role here. Andreas started with the Feistel
Network theory and lead the break out. It is amazing what you can get making two genius
work together!
</p>
        <p>
In case you haven't heard of Andreas, he's a very clever spanish guy that also helped
to reverse engineer the DSP-1 chip used in Mario Kart and the S-DD1 used in Star Ocean.
</p>
        <p>
There are some pieces of the puzzle to complete to fully understand the encryption
but having reached that far it can only get better ;-)
</p>
        <p>
Take a detailed look at their blogs to know more about this amazing achievement!
</p>
        <p>
          <a href="http://andreasnaive.blogspot.com/">http://andreasnaive.blogspot.com/</a>
        </p>
        <p>
          <a href="http://mamelife.blogspot.com/">http://mamelife.blogspot.com/</a>
        </p>
        <p>
Hats off to you guys!<br /></p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a44d4086-0b51-4a94-93c0-313f51ecb86e" />
      </body>
      <title>CPS2 Encryption (almost) understood!</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,a44d4086-0b51-4a94-93c0-313f51ecb86e.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,a44d4086-0b51-4a94-93c0-313f51ecb86e.aspx</link>
      <pubDate>Tue, 09 Jan 2007 23:44:38 GMT</pubDate>
      <description>&lt;p&gt;
Nicola Salmoria was able to decrypt a complete CPS2 game algorithmically without using
any table!
&lt;/p&gt;
&lt;p&gt;
Well, to be fair Andreas Naive played a key role here. Andreas started with the Feistel
Network theory and lead the break out. It is amazing what you can get making two genius
work together!
&lt;/p&gt;
&lt;p&gt;
In case you haven't heard of Andreas, he's a very clever spanish guy that also helped
to reverse engineer the DSP-1 chip used in Mario Kart and the S-DD1 used in Star Ocean.
&lt;/p&gt;
&lt;p&gt;
There are some pieces of the puzzle to complete to fully understand the encryption
but having reached that far it can only get better ;-)
&lt;/p&gt;
&lt;p&gt;
Take a detailed look at their blogs to know more about this amazing achievement!
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://andreasnaive.blogspot.com/"&gt;http://andreasnaive.blogspot.com/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://mamelife.blogspot.com/"&gt;http://mamelife.blogspot.com/&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Hats off to you guys!&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=a44d4086-0b51-4a94-93c0-313f51ecb86e" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,a44d4086-0b51-4a94-93c0-313f51ecb86e.aspx</comments>
      <category>Games;MAME</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=1981d708-5949-4d87-b7f4-ae60df47b298</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,1981d708-5949-4d87-b7f4-ae60df47b298.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,1981d708-5949-4d87-b7f4-ae60df47b298.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1981d708-5949-4d87-b7f4-ae60df47b298</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Another year ends and a new one comes. Life goes as fast as usual and we’re keep
on our way. It’s time to think about it… our actions, hopes, wishes, mistakes,
etc. 
</p>
        <p>
I usually listen to a special song a few minutes after the start of the year.
In the last few years I have been choosing "Aerosmith – Full Circle" because it has
special connotations for me. 
</p>
        <p>
I wish you the best in the coming year.
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=1981d708-5949-4d87-b7f4-ae60df47b298" />
      </body>
      <title>Happy 2007!</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,1981d708-5949-4d87-b7f4-ae60df47b298.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,1981d708-5949-4d87-b7f4-ae60df47b298.aspx</link>
      <pubDate>Mon, 01 Jan 2007 23:36:54 GMT</pubDate>
      <description>&lt;p&gt;
Another year ends and a new one comes. Life goes as fast as usual and we’re&amp;nbsp;keep
on&amp;nbsp;our way. It’s time to think about it… our actions, hopes, wishes, mistakes,
etc. 
&lt;/p&gt;
&lt;p&gt;
I usually listen to a special song&amp;nbsp;a few minutes after the start of the year.
In the last few years I have been choosing "Aerosmith – Full Circle" because it has
special connotations for me. 
&lt;/p&gt;
&lt;p&gt;
I wish you the best in the coming year.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=1981d708-5949-4d87-b7f4-ae60df47b298" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,1981d708-5949-4d87-b7f4-ae60df47b298.aspx</comments>
      <category>Ajax;ANTLR;ASP.NET;CSS;Games;General;JavaScript;Microsoft .NET Framework;Music;WPF/E</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=bb9fec54-5c51-41a3-aaa2-21abddd41458</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,bb9fec54-5c51-41a3-aaa2-21abddd41458.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,bb9fec54-5c51-41a3-aaa2-21abddd41458.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=bb9fec54-5c51-41a3-aaa2-21abddd41458</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
My girlfriend sent me this Excel spreadsheet where you have guess some old games based
on the screenshots. 
</p>
        <img src="http://www.manuelabadia.com/blog/content/binary/marcianitos_spreadsheet.jpg" />
        <p>
A funny way to spend 5 minutes. I scored 60 out of 65 (I was too young for some of
the games).
</p>
        <p>
There’s a bug in one name: instead of operation you have to type operación.
</p>
        <p>
Have fun!<br /></p>
        <a href="http://www.manuelabadia.com/blog/content/binary/marcianitos_blank.zip">SpreadSheet.zip
729 KB</a>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=bb9fec54-5c51-41a3-aaa2-21abddd41458" />
      </body>
      <title>Guess the game</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,bb9fec54-5c51-41a3-aaa2-21abddd41458.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,bb9fec54-5c51-41a3-aaa2-21abddd41458.aspx</link>
      <pubDate>Sun, 26 Mar 2006 13:37:08 GMT</pubDate>
      <description>&lt;p&gt;
My girlfriend sent me this Excel spreadsheet where you have guess some old games based
on the screenshots. 
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/marcianitos_spreadsheet.jpg"&gt;&gt; 
&lt;p&gt;
A funny way to spend 5 minutes. I scored 60 out of 65 (I was too young for some of
the games).
&lt;/p&gt;
&lt;p&gt;
There’s a bug in one name: instead of operation you have to type operación.
&lt;/p&gt;
&lt;p&gt;
Have fun!&lt;br&gt;
&lt;/p&gt;
&lt;a href="http://www.manuelabadia.com/blog/content/binary/marcianitos_blank.zip"&gt;SpreadSheet.zip
729 KB&lt;/a&gt;&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=bb9fec54-5c51-41a3-aaa2-21abddd41458" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,bb9fec54-5c51-41a3-aaa2-21abddd41458.aspx</comments>
      <category>Games</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=658de6b6-4fae-48cc-bb0a-f5593cf336ac</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,658de6b6-4fae-48cc-bb0a-f5593cf336ac.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,658de6b6-4fae-48cc-bb0a-f5593cf336ac.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=658de6b6-4fae-48cc-bb0a-f5593cf336ac</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in Spanish and then in English.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Esta es la última noticia relativa al Trivial Pursuit en español. Si no has leído
las noticias anteriores puedes hacerlo aquí:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</a>
        </p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</a>
        </p>
        <p>
De la última semana teníamos la siguiente configuración de las ROMs:<br />
0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
y ya sabíamos como iba la rutina que mostraba las frases en pantalla.
</p>
        <p>
Si continuamos entendiendo el código, llegamos al bucle principal del juego, donde
se realiza una serie de tareas determinadas por el estado actual.<br />
Estudiando los diferentes estados del juego podemos averiguar cualquier cosa que queramos
sobre él. Os adjunto una captura de los distintos estados del juego:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/mainloop.png" border="0" />
        </p>
        <p>
Si estudiamos el estado cuando la variable vale 0x04, es decir, cuando se muestra
una pregunta, llegamos al fin a la rutina que muestra las preguntas por pantalla (dicha
rutina está en $f390). Esta rutina es bastante larga y compleja, por lo que no la
voy a detallar. Sin embargo, resulta curioso saber cómo se guardan las preguntas y
las respuestas del juego.
</p>
        <p>
Las preguntas se guardan con 2 punteros. El primero indica el tipo de pregunta que
es y el segundo la pregunta en si. Un ejemplo deja esto más claro: La pregunta: "¿Cual
fue el primer monarca europeo que visitó china?" tiene un puntero a "Cual" y a "fue
el primer monarca europeo que visitó china". Gracias a este esquema se ahorran unos
cuantos bytes puesto que todas las preguntas empiezan por un conjunto reducido de
frases del tipo Cuándo, Qué, Quién, De quienes, etc. Esto es solo la primera parte,
puesto que los punteros apuntan a frases que tienen los caracteres codificados en
base 40, de forma que en 2 bytes se pueden meter 3 caracteres. De nuevo un ejemplo
es lo mejor para entender esto.<br />
 <br />
Si tenemos los bytes:<br />
0x42 0x80 0x55 0x27<br />
 <br />
los agrupamos de 2 en 2 y para cada 2 bytes obtenemos los 3 dígitos que componen ese
número en base 40. Por si no andáis muy puestos en cambios de base, si quisiéramos
obtener los dígitos que componen el número 379 en base 10, obtendríamos 3, 7 y 9,
puesto que 379 dividido entre 10^2 da 3 y de resto 79. 79 dividido entre 10^1 da 7
y de resto 9, y 9 entre 10^0 da 9, es decir, 379 = 3*10^2 + 7*10^1 + 9*10^0.
</p>
        <p>
Para base 40 es similar pero dividiendo entre 40. Para el número 0x4280 obtenemos
10, 25 y 24 (en hexadecimal 0x0a, 0x19 y 0x18), y para 0x5527 obtenemos 13, 24 y 39
(en hexadecimal 0x0d, 0x18 y 0x27).
</p>
        <p>
Una vez que se obtienen los 3 dígitos de los 2 bytes, se mandan a la rutina que vimos
la semana pasada para mostrar frases por pantalla, aunque se hace un ligero ajuste
al principio. Si recordáis lo que dije la semana pasada, la rutina para mostrar caracteres
por pantalla hacía la siguiente conversión:<br />
0x00-0x09 -&gt; números del 0 al 9<br />
0x0a-0x23 -&gt; caracteres de la 'a' a la 'z'<br />
0x27-&gt; espacio<br />
0x32-0x4b -&gt; caracteres de la 'A' a la 'Z'
</p>
        <p>
Si comprobamos los valores que habíamos obtenido anteriormente, tenemos:<br />
0x0a -&gt; a, 0x19 -&gt; p, 0x18 -&gt; o, 0x0d -&gt; d, 0x18 -&gt; o, 0x27 -&gt; espacio
en blanco<br />
por lo que los bytes 0x42 0x80 0x55 0x27 codifican "apodo ".
</p>
        <p>
Como el juego guarda los caracteres a imprimir en base 40, tan solo se dispone de
40 caracteres distintos para representar las preguntas. Sin embargo, los números más
las letras en minúscula ya hacen un total de 36 valores distintos, por lo que no habría
forma de mostrar mayúsculas ni todos los acentos así como signos de puntuación. Para
evitar este problema, el juego utiliza el valor 0x24 como marcador para indicar que
el siguiente byte que se lea se escribirá sumándole 0x28, de forma que si quisiéramos
escribir Apodo en vez de apodo deberíamos tener los valores:<br />
0x28 0x0a 0x19 0x18 0x0d 0x18
</p>
        <p>
Una vez entendido esto, no tenemos más que creamos un programa en C# que muestre todas
las frases que encuentre en las ROMs:
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Collections.Generic;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.IO;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Text;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">namespace</span> Trivial
</p>
          <p style="MARGIN: 0px">
{
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">class</span><span style="COLOR: teal">Program2</span></p>
          <p style="MARGIN: 0px">
    {
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">protected</span><span style="COLOR: blue">static</span><span style="COLOR: blue">bool</span> ignorar;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">static</span><span style="COLOR: blue">void</span> Main(<span style="COLOR: blue">string</span>[]
args)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (args.Length
!= 2){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: teal">Console</span>.WriteLine(<span style="COLOR: maroon">"Error,
se necesitan 2 argumentos: &lt;rom&gt; &lt;salida.txt&gt;"</span>);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> input
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[0]);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> output
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[1]);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StreamWriter</span> writer
= output.CreateText();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileStream</span> fileStream
= input.Open(<span style="COLOR: teal">FileMode</span>.Open);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">BinaryReader</span> br
= <span style="COLOR: blue">new</span><span style="COLOR: teal">BinaryReader</span>(fileStream);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
romData = br.ReadBytes(0x4000);
</p>
          <p style="MARGIN: 0px">
            br.Close();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StringBuilder</span> sb
= <span style="COLOR: blue">new</span><span style="COLOR: teal">StringBuilder</span>();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> i
= 0;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> startOffset
= 0;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
recorre la ROM grabando las frases que encuentre</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">while</span> (i
&lt; (0x4000 - 1)) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
0xff marca el fín de la frase, por lo que la escribe</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (romData[i]
== 0xff) {
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">if</span> (sb.Length
&gt; 0) {
</p>
          <p style="MARGIN: 0px">
                   
    writer.WriteLine(<span style="COLOR: teal">String</span>.Format(<span style="COLOR: maroon">"{0:X}:
{1}"</span>, startOffset, sb.ToString()));
</p>
          <p style="MARGIN: 0px">
                   
    sb.Length = 0;
</p>
          <p style="MARGIN: 0px">
                   
}
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                   
i++;
</p>
          <p style="MARGIN: 0px">
                   
startOffset = i;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">continue</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
convierte 2 bytes en 3 digitos en base 40</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">int</span> num
= (romData[i] &lt;&lt; 8) | (romData[i + 1]);
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">byte</span>[]
caracteres = CambioBase(num, 40, 3);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
escribe los dígitos</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">foreach</span> (<span style="COLOR: blue">byte</span> caracter <span style="COLOR: blue">in</span> caracteres)
{
</p>
          <p style="MARGIN: 0px">
                   
sb.Append(Convertir(caracter));
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                i += 2;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            writer.WriteLine(sb.ToString());
</p>
          <p style="MARGIN: 0px">
            writer.Close();
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// devuelve un array
de bytes con los dígitos del cambio de base</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">byte</span>[]
CambioBase(<span style="COLOR: blue">int</span> valor, <span style="COLOR: blue">int</span> baseNum, <span style="COLOR: blue">int</span> numDigitos)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
resultado = <span style="COLOR: blue">new</span><span style="COLOR: blue">byte</span>[numDigitos];
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> pos
= numDigitos - 1;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">do</span> {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">byte</span> digito
= (<span style="COLOR: blue">byte</span>)(valor % baseNum);
</p>
          <p style="MARGIN: 0px">
                valor
= valor / baseNum;
</p>
          <p style="MARGIN: 0px">
                resultado[pos]
= digito;
</p>
          <p style="MARGIN: 0px">
                pos--;
</p>
          <p style="MARGIN: 0px">
            } <span style="COLOR: blue">while</span> (pos
&gt;= 0);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span> resultado;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// se encarga de
convertir un byte al código ASCII correspondiente</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">string</span> Convertir(<span style="COLOR: blue">byte</span> data)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">string</span> str
= <span style="COLOR: maroon">"#"</span>;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
números</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x00) &amp;&amp; (data &lt;= 0x09)){
</p>
          <p style="MARGIN: 0px">
                str = <span style="COLOR: blue">new</span><span style="COLOR: blue">string</span>((<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'0'</span>)
+ (data - 0x00)), 1);
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras minúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x0a) &amp;&amp; (data &lt;= 0x23)){
</p>
          <p style="MARGIN: 0px">
                str = <span style="COLOR: blue">new</span><span style="COLOR: blue">string</span>((<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'a'</span>)
+ (data - 0x0a)), 1);
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
usado para convertir a mayúsculas o para poner acentos</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x24) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span><span style="COLOR: maroon">""</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
espacio o fín de entrada</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x27) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (ignorar)
{
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">return</span><span style="COLOR: maroon">""</span>;
</p>
          <p style="MARGIN: 0px">
                } <span style="COLOR: blue">else</span> {
</p>
          <p style="MARGIN: 0px">
                   
ignorar = <span style="COLOR: blue">true</span>;
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">return</span><span style="COLOR: maroon">"
"</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            ignorar = <span style="COLOR: blue">false</span>;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span> str;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
    }
</p>
          <p style="MARGIN: 0px">
}
</p>
        </div>
        <!--EndFragment-->
        <p>
 
</p>
        <p>
Al ejecutar el programa obtenemos muchas preguntas y respuestas en varias ROMs:
</p>
        <p>
[...]
</p>
        <p>
39a: nombre dieron los romanos a las islas canarias<br />
3bb: llamamos en espa#ol a la ciudad alemana de koln 
<br />
3de: de los ap3stoles alfab1ticamente es el primero<br />
3ff: lugar est0 #la creaci3n del hombre# de miguel angel 
<br />
426: de los evangelios cuenta que un ni#o le llev3 a jes4s 5 panes y 2 peces 
<br />
45b: dos paises hay cadenas monta#osas llamadas sierra nevada 
<br />
484: tienen como patr3n a san nicol0s<br />
49d: hero2na se abras3 en 1431<br />
4b0: continente no tiene ciudades capitales 
</p>
        <p>
[...]
</p>
        <p>
8FB: australiana<br />
904: ava gardner 
<br />
90F: sara montiel 
<br />
91A: gina lollobrigida 
<br />
929: brigitte bardot 
<br />
936: susana estrada 
<br />
943: arthur miller<br />
94E: hern0ndez mancha 
<br />
95D: john ford 
<br />
966: juan pablo ii 
<br />
973: ernesto iv 
</p>
        <p>
[...]
</p>
        <p>
Por lo que ya tenemos un poco más claro que hay en las ROMs que no tenemos mapeadas
correctamente:<br />
TP_A2.BIN -&gt; preguntas<br />
TP_A4.BIN -&gt; respuestas<br />
TP_A6.BIN -&gt; ni preguntas ni respuestas, sino que hay datos de otro tipo<br />
TP_A7.BIN -&gt; preguntas y respuestas<br />
TP_A8.BIN -&gt; preguntas y respuestas
</p>
        <p>
La misma rutina que decodifica las preguntas utiliza 2 bancos distintos para obtener
los punteros que forman la preguntas y sus respuestas, 4 bancos distintos para obtener
el texto de las preguntas y otros 4 bancos distintos para obtener el texto de las
respuestas. Como cada ROM tiene 2 bancos, gracias a la información obtenida tenemos:
</p>
        <p>
La ROM TP_A6.BIN ya está mapeada correctamente.<br />
Para las preguntas tenemos 4 opciones y para las respuestas otras 4 opciones por lo
que el número total de combinaciones queda reducido a 8. El único problema es que
la máquina tiene un generador de números aleatorios, por lo que si nos decantamos
por la opción de probar las 8 combinaciones distintas, tenemos que trucar el generador
de números aleatorios para que siempre estemos probando colocar las ROMs para la misma
pregunta.
</p>
        <p>
Tras 3 o 4 pruebas al fín obtenemos la combinación correcta:
</p>
        <p>
0x10000-0x13fff TP_A2.BIN<br />
0x14000-0x17fff TP_A7.BIN<br />
0x18000-0x1bfff TP_A4.BIN<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff TP_A8.BIN<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff TP_A6.BIN<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
Como para acertarla sin haber estudiado el juego a fondo...
</p>
        <p>
Aquí tenéis unas pantallas con el juego funcionando correctamente:
</p>
        <table>
          <tbody>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_008.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_009.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_010.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_011.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_012.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_013.png" border="0" />
              </td>
            </tr>
          </tbody>
        </table>
        <p>
Le doy los últimos repasos al driver y lo envío a la lista del MAME.
</p>
        <p>
Espero que disfrutéis del juego muy pronto. Probablemente sea mi último driver para
el MAME.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
This is the third post about Trivial Pursuit Spanish. If you haven't read the previous
ones you can do it here:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</a>
        </p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</a>
        </p>
        <p>
Last week we had the following ROM configuration:<br />
 0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
If we continue understanding code we reach the main loop of the game, where the code
jumps to a routine based on the current state. Here’s the method I’m talking about:
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/mainloop.png" border="0" />
        </p>
        <p>
If we carefully study what happens in the state 0x04, where the game shows a question,
we finally found how the questions and answers are coded (routine at $f390). That
routine is large so I’m not going to show it but it’s curious to know how the questions
and answers were stored.
</p>
        <p>
A question is defined by 2 pointers. The first one is the start of the question and
the second one the core of the question. An example will explain this better than
me: The question: “Who was the first king that visited china?” has the first pointer
pointing to the sentence “Who” and the second one to “was the first king that visited
china”. Thanks to this schema they save a few bytes per question.
</p>
        <p>
This is only the first part as the characters for the sentences are coded in base
40. 3 characters are coded in 2 bytes. Again an example is the best to explain this:<br />
 <br />
If we have the following bytes:<br />
0x42 0x80 0x55 0x27<br />
 <br />
We take 2 bytes at a time and extract 3 base 40 digits so for 0x4280 we’ve got 10,
25 and 24 (0x0a, 0x19 and 0x18 in hexadecimal), and for 0x5527 we’ve got 13, 24 and
39 (0x0d, 0x18 and 0x27 in hexadecimal).
</p>
        <p>
After having the values, they’re sent to the routine we saw last week that printed
characters. That routine did the following conversion:<br />
0x00-0x09 -&gt; numbers from 0 to 9<br />
0x0a-0x23 -&gt; characters from 'a' to 'z'<br />
0x27-&gt; space<br />
0x32-0x4b -&gt; characters from 'A' to 'Z'
</p>
        <p>
If we check what we obtained previously:<br />
0x0a -&gt; a, 0x19 -&gt; p, 0x18 -&gt; o, 0x0d -&gt; d, 0x18 -&gt; o, 0x27 -&gt; space<br />
So the following bytes: 0x42 0x80 0x55 0x27 store "apodo " (spanish word for nickname).
</p>
        <p>
As the game stores the characters using base 40 codification, we can store only 40
characters, but the digits and lowercase letters make a total of 36 characters and
we are still missing punctuation marks, uppercase letters, etc. To solve that problem,
the game uses the value 0x24 as a marker to indicate that the character will be written
adding 0x28 to the next value. If we want to write Apodo instead of apodo we would
need the values:<br />
0x28 0x0a 0x19 0x18 0x0d 0x18
</p>
        <p>
With this information we can write a C# program that searchs all sentences in a ROM:
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Collections.Generic;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.IO;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Text;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">namespace</span> Trivial
</p>
          <p style="MARGIN: 0px">
{
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">class</span><span style="COLOR: teal">Program2</span></p>
          <p style="MARGIN: 0px">
    {
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">protected</span><span style="COLOR: blue">static</span><span style="COLOR: blue">bool</span> ignorar;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">static</span><span style="COLOR: blue">void</span> Main(<span style="COLOR: blue">string</span>[]
args)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (args.Length
!= 2){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: teal">Console</span>.WriteLine(<span style="COLOR: maroon">"Error,
se necesitan 2 argumentos: &lt;rom&gt; &lt;salida.txt&gt;"</span>);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> input
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[0]);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> output
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[1]);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StreamWriter</span> writer
= output.CreateText();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileStream</span> fileStream
= input.Open(<span style="COLOR: teal">FileMode</span>.Open);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">BinaryReader</span> br
= <span style="COLOR: blue">new</span><span style="COLOR: teal">BinaryReader</span>(fileStream);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
romData = br.ReadBytes(0x4000);
</p>
          <p style="MARGIN: 0px">
            br.Close();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StringBuilder</span> sb
= <span style="COLOR: blue">new</span><span style="COLOR: teal">StringBuilder</span>();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> i
= 0;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> startOffset
= 0;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
recorre la ROM grabando las frases que encuentre</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">while</span> (i
&lt; (0x4000 - 1)) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
0xff marca el fín de la frase, por lo que la escribe</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (romData[i]
== 0xff) {
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">if</span> (sb.Length
&gt; 0) {
</p>
          <p style="MARGIN: 0px">
                   
    writer.WriteLine(<span style="COLOR: teal">String</span>.Format(<span style="COLOR: maroon">"{0:X}:
{1}"</span>, startOffset, sb.ToString()));
</p>
          <p style="MARGIN: 0px">
                   
    sb.Length = 0;
</p>
          <p style="MARGIN: 0px">
                   
}
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                   
i++;
</p>
          <p style="MARGIN: 0px">
                   
startOffset = i;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">continue</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
convierte 2 bytes en 3 digitos en base 40</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">int</span> num
= (romData[i] &lt;&lt; 8) | (romData[i + 1]);
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">byte</span>[]
caracteres = CambioBase(num, 40, 3);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
escribe los dígitos</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">foreach</span> (<span style="COLOR: blue">byte</span> caracter <span style="COLOR: blue">in</span> caracteres)
{
</p>
          <p style="MARGIN: 0px">
                   
sb.Append(Convertir(caracter));
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                i += 2;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            writer.WriteLine(sb.ToString());
</p>
          <p style="MARGIN: 0px">
            writer.Close();
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// devuelve un array
de bytes con los dígitos del cambio de base</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">byte</span>[]
CambioBase(<span style="COLOR: blue">int</span> valor, <span style="COLOR: blue">int</span> baseNum, <span style="COLOR: blue">int</span> numDigitos)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
resultado = <span style="COLOR: blue">new</span><span style="COLOR: blue">byte</span>[numDigitos];
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">int</span> pos
= numDigitos - 1;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">do</span> {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">byte</span> digito
= (<span style="COLOR: blue">byte</span>)(valor % baseNum);
</p>
          <p style="MARGIN: 0px">
                valor
= valor / baseNum;
</p>
          <p style="MARGIN: 0px">
                resultado[pos]
= digito;
</p>
          <p style="MARGIN: 0px">
                pos--;
</p>
          <p style="MARGIN: 0px">
            } <span style="COLOR: blue">while</span> (pos
&gt;= 0);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span> resultado;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// se encarga de
convertir un byte al código ASCII correspondiente</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">string</span> Convertir(<span style="COLOR: blue">byte</span> data)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">string</span> str
= <span style="COLOR: maroon">"#"</span>;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
números</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x00) &amp;&amp; (data &lt;= 0x09)){
</p>
          <p style="MARGIN: 0px">
                str = <span style="COLOR: blue">new</span><span style="COLOR: blue">string</span>((<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'0'</span>)
+ (data - 0x00)), 1);
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras minúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x0a) &amp;&amp; (data &lt;= 0x23)){
</p>
          <p style="MARGIN: 0px">
                str = <span style="COLOR: blue">new</span><span style="COLOR: blue">string</span>((<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'a'</span>)
+ (data - 0x0a)), 1);
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
usado para convertir a mayúsculas o para poner acentos</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x24) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span><span style="COLOR: maroon">""</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
espacio o fín de entrada</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x27) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (ignorar)
{
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">return</span><span style="COLOR: maroon">""</span>;
</p>
          <p style="MARGIN: 0px">
                } <span style="COLOR: blue">else</span> {
</p>
          <p style="MARGIN: 0px">
                   
ignorar = <span style="COLOR: blue">true</span>;
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">return</span><span style="COLOR: maroon">"
"</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            ignorar = <span style="COLOR: blue">false</span>;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span> str;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
    }
</p>
          <p style="MARGIN: 0px">
}
</p>
        </div>
        <!--EndFragment-->
        <p>
 
</p>
        <p>
If we run the program we get a lot of questions and answers in several ROMs: 
</p>
        <p>
[...]
</p>
        <p>
39a: nombre dieron los romanos a las islas canarias<br />
3bb: llamamos en espa#ol a la ciudad alemana de koln 
<br />
3de: de los ap3stoles alfab1ticamente es el primero<br />
3ff: lugar est0 #la creaci3n del hombre# de miguel angel 
<br />
426: de los evangelios cuenta que un ni#o le llev3 a jes4s 5 panes y 2 peces 
<br />
45b: dos paises hay cadenas monta#osas llamadas sierra nevada 
<br />
484: tienen como patr3n a san nicol0s<br />
49d: hero2na se abras3 en 1431<br />
4b0: continente no tiene ciudades capitales 
</p>
        <p>
[...]
</p>
        <p>
8FB: australiana<br />
904: ava gardner 
<br />
90F: sara montiel 
<br />
91A: gina lollobrigida 
<br />
929: brigitte bardot 
<br />
936: susana estrada 
<br />
943: arthur miller<br />
94E: hern0ndez mancha 
<br />
95D: john ford 
<br />
966: juan pablo ii 
<br />
973: ernesto iv 
</p>
        <p>
[...]
</p>
        <p>
So now we know what is inside the ROMs we don’t know how to map:<br />
TP_A2.BIN -&gt; questions<br />
TP_A4.BIN -&gt; answers<br />
TP_A6.BIN -&gt; unknown data<br />
TP_A7.BIN -&gt; questions and answers<br />
TP_A8.BIN -&gt; questions and answers
</p>
        <p>
The same routine that decodes the questions and answers uses up to 4 different banks
to select a question, up to 4 different banks to select an answer and 2 banks to get
the pointers to the questions and answers, so thanks to that information we can map
ROM TP_A6.BIN and reduce the number of possible combinations to 8.
</p>
        <p>
After a few tries we finally found the proper combination:
</p>
        <p>
0x10000-0x13fff TP_A2.BIN<br />
0x14000-0x17fff TP_A7.BIN<br />
0x18000-0x1bfff TP_A4.BIN<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff TP_A8.BIN<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff TP_A6.BIN<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
Some screenshots of the game running:
</p>
        <table>
          <tbody>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_008.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_009.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_010.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_011.png" border="0" />
              </td>
            </tr>
            <tr>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_012.png" border="0" />
              </td>
              <td>
                <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_013.png" border="0" />
              </td>
            </tr>
          </tbody>
        </table>
        <p>
I’ll tidy up the code and send it to the MAMEDEV list.<br /></p>
        <p>
        </p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=658de6b6-4fae-48cc-bb0a-f5593cf336ac" />
      </body>
      <title>finished MAME driver for Trivial Pursuit (Spanish)</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,658de6b6-4fae-48cc-bb0a-f5593cf336ac.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,658de6b6-4fae-48cc-bb0a-f5593cf336ac.aspx</link>
      <pubDate>Sun, 12 Mar 2006 00:41:15 GMT</pubDate>
      <description>&lt;p&gt;
This post is first in Spanish and then in English.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Esta es la última noticia relativa al Trivial Pursuit en español. Si no has leído
las noticias anteriores puedes hacerlo aquí:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
De la última semana teníamos la siguiente configuración de las ROMs:&lt;br&gt;
0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
y ya sabíamos como iba la rutina que mostraba las frases en pantalla.
&lt;/p&gt;
&lt;p&gt;
Si continuamos entendiendo el código, llegamos al bucle principal del juego, donde
se realiza una serie de tareas determinadas por el estado actual.&lt;br&gt;
Estudiando los diferentes estados del juego podemos averiguar cualquier cosa que queramos
sobre él. Os adjunto una captura de los distintos estados del juego:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/mainloop.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Si estudiamos el estado cuando la variable vale 0x04, es decir, cuando se muestra
una pregunta, llegamos al fin a la rutina que muestra las preguntas por pantalla (dicha
rutina está en $f390). Esta rutina es bastante larga y compleja, por lo que no la
voy a detallar. Sin embargo, resulta curioso saber cómo se guardan las preguntas y
las respuestas del juego.
&lt;/p&gt;
&lt;p&gt;
Las preguntas se guardan con 2 punteros. El primero indica el tipo de pregunta que
es y el segundo la pregunta en si. Un ejemplo deja esto más claro: La pregunta: "¿Cual
fue el primer monarca europeo que visitó china?" tiene un puntero a "Cual" y a "fue
el primer monarca europeo que visitó china". Gracias a este esquema se ahorran unos
cuantos bytes puesto que todas las preguntas empiezan por un conjunto reducido de
frases del tipo Cuándo, Qué, Quién, De quienes, etc. Esto es solo la primera parte,
puesto que los punteros apuntan a frases que tienen los caracteres codificados en
base 40, de forma que en 2 bytes se pueden meter 3 caracteres. De nuevo un ejemplo
es lo mejor para entender esto.&lt;br&gt;
&amp;nbsp;&lt;br&gt;
Si tenemos los bytes:&lt;br&gt;
0x42 0x80 0x55 0x27&lt;br&gt;
&amp;nbsp;&lt;br&gt;
los agrupamos de 2 en 2 y para cada 2 bytes obtenemos los 3 dígitos que componen ese
número en base 40. Por si no andáis muy puestos en cambios de base, si quisiéramos
obtener los dígitos que componen el número 379 en base 10, obtendríamos 3, 7 y 9,
puesto que 379 dividido entre 10^2 da 3 y de resto 79. 79 dividido entre 10^1 da 7
y de resto 9, y 9 entre 10^0 da 9, es decir, 379 = 3*10^2 + 7*10^1 + 9*10^0.
&lt;/p&gt;
&lt;p&gt;
Para base 40 es similar pero dividiendo entre 40. Para el número 0x4280 obtenemos
10, 25 y 24 (en hexadecimal 0x0a, 0x19 y 0x18), y para 0x5527 obtenemos 13, 24 y 39
(en hexadecimal 0x0d, 0x18 y 0x27).
&lt;/p&gt;
&lt;p&gt;
Una vez que se obtienen los 3 dígitos de los 2 bytes, se mandan a la rutina que vimos
la semana pasada para mostrar frases por pantalla, aunque se hace un ligero ajuste
al principio. Si recordáis lo que dije la semana pasada, la rutina para mostrar caracteres
por pantalla hacía la siguiente conversión:&lt;br&gt;
0x00-0x09 -&amp;gt; números del 0 al 9&lt;br&gt;
0x0a-0x23 -&amp;gt; caracteres de la 'a' a la 'z'&lt;br&gt;
0x27-&amp;gt; espacio&lt;br&gt;
0x32-0x4b -&amp;gt; caracteres de la 'A' a la 'Z'
&lt;/p&gt;
&lt;p&gt;
Si comprobamos los valores que habíamos obtenido anteriormente, tenemos:&lt;br&gt;
0x0a -&amp;gt; a, 0x19 -&amp;gt; p, 0x18 -&amp;gt; o, 0x0d -&amp;gt; d, 0x18 -&amp;gt; o, 0x27 -&amp;gt; espacio
en blanco&lt;br&gt;
por lo que los bytes 0x42 0x80 0x55 0x27 codifican "apodo ".
&lt;/p&gt;
&lt;p&gt;
Como el juego guarda los caracteres a imprimir en base 40, tan solo se dispone de
40 caracteres distintos para representar las preguntas. Sin embargo, los números más
las letras en minúscula ya hacen un total de 36 valores distintos, por lo que no habría
forma de mostrar mayúsculas ni todos los acentos así como signos de puntuación. Para
evitar este problema, el juego utiliza el valor 0x24 como marcador para indicar que
el siguiente byte que se lea se escribirá sumándole 0x28, de forma que si quisiéramos
escribir Apodo en vez de apodo deberíamos tener los valores:&lt;br&gt;
0x28 0x0a 0x19 0x18 0x0d 0x18
&lt;/p&gt;
&lt;p&gt;
Una vez entendido esto, no tenemos más que creamos un programa en C# que muestre todas
las frases que encuentre en las ROMs:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.IO;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Text;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; Trivial
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Program2&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;protected&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; ignorar;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; Main(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
args)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (args.Length
!= 2){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="COLOR: maroon"&gt;"Error,
se necesitan 2 argumentos: &amp;lt;rom&amp;gt; &amp;lt;salida.txt&amp;gt;"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; input
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[0]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; output
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StreamWriter&lt;/span&gt; writer
= output.CreateText();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileStream&lt;/span&gt; fileStream
= input.Open(&lt;span style="COLOR: teal"&gt;FileMode&lt;/span&gt;.Open);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt; br
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt;(fileStream);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
romData = br.ReadBytes(0x4000);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; br.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt; sb
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; i
= 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; startOffset
= 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
recorre la ROM grabando las frases que encuentre&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;while&lt;/span&gt; (i
&amp;lt; (0x4000 - 1)) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
0xff marca el fín de la frase, por lo que la escribe&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (romData[i]
== 0xff) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sb.Length
&amp;gt; 0) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(&lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Format(&lt;span style="COLOR: maroon"&gt;"{0:X}:
{1}"&lt;/span&gt;, startOffset, sb.ToString()));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Length = 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
i++;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
startOffset = i;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;continue&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
convierte 2 bytes en 3 digitos en base 40&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; num
= (romData[i] &amp;lt;&amp;lt; 8) | (romData[i + 1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
caracteres = CambioBase(num, 40, 3);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
escribe los dígitos&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; caracter &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; caracteres)
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
sb.Append(Convertir(caracter));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; i += 2;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(sb.ToString());
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// devuelve un array
de bytes con los dígitos del cambio de base&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
CambioBase(&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; valor, &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; baseNum, &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; numDigitos)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
resultado = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[numDigitos];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; pos
= numDigitos - 1;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;do&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; digito
= (&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;)(valor % baseNum);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; valor
= valor / baseNum;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; resultado[pos]
= digito;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; pos--;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="COLOR: blue"&gt;while&lt;/span&gt; (pos
&amp;gt;= 0);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; resultado;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// se encarga de
convertir un byte al código ASCII correspondiente&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; Convertir(&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; data)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; str
= &lt;span style="COLOR: maroon"&gt;"#"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
números&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x00) &amp;amp;&amp;amp; (data &amp;lt;= 0x09)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; str = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;((&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'0'&lt;/span&gt;)
+ (data - 0x00)), 1);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras minúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x0a) &amp;amp;&amp;amp; (data &amp;lt;= 0x23)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; str = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;((&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'a'&lt;/span&gt;)
+ (data - 0x0a)), 1);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
usado para convertir a mayúsculas o para poner acentos&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x24) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;""&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
espacio o fín de entrada&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x27) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (ignorar)
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;""&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
ignorar = &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;"
"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ignorar = &lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; str;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Al ejecutar el programa obtenemos muchas preguntas y respuestas en varias ROMs:
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
39a: nombre dieron los romanos a las islas canarias&lt;br&gt;
3bb: llamamos en espa#ol a la ciudad alemana de koln 
&lt;br&gt;
3de: de los ap3stoles alfab1ticamente es el primero&lt;br&gt;
3ff: lugar est0 #la creaci3n del hombre# de miguel angel 
&lt;br&gt;
426: de los evangelios cuenta que un ni#o le llev3 a jes4s 5 panes y 2 peces 
&lt;br&gt;
45b: dos paises hay cadenas monta#osas llamadas sierra nevada 
&lt;br&gt;
484: tienen como patr3n a san nicol0s&lt;br&gt;
49d: hero2na se abras3 en 1431&lt;br&gt;
4b0: continente no tiene ciudades capitales 
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
8FB: australiana&lt;br&gt;
904: ava gardner 
&lt;br&gt;
90F: sara montiel 
&lt;br&gt;
91A: gina lollobrigida 
&lt;br&gt;
929: brigitte bardot 
&lt;br&gt;
936: susana estrada 
&lt;br&gt;
943: arthur miller&lt;br&gt;
94E: hern0ndez mancha 
&lt;br&gt;
95D: john ford 
&lt;br&gt;
966: juan pablo ii 
&lt;br&gt;
973: ernesto iv 
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
Por lo que ya tenemos un poco más claro que hay en las ROMs que no tenemos mapeadas
correctamente:&lt;br&gt;
TP_A2.BIN -&amp;gt; preguntas&lt;br&gt;
TP_A4.BIN -&amp;gt; respuestas&lt;br&gt;
TP_A6.BIN -&amp;gt; ni preguntas ni respuestas, sino que hay datos de otro tipo&lt;br&gt;
TP_A7.BIN -&amp;gt; preguntas y respuestas&lt;br&gt;
TP_A8.BIN -&amp;gt; preguntas y respuestas
&lt;/p&gt;
&lt;p&gt;
La misma rutina que decodifica las preguntas utiliza 2 bancos distintos para obtener
los punteros que forman la preguntas y sus respuestas, 4 bancos distintos para obtener
el texto de las preguntas y otros 4 bancos distintos para obtener el texto de las
respuestas. Como cada ROM tiene 2 bancos, gracias a la información obtenida tenemos:
&lt;/p&gt;
&lt;p&gt;
La ROM TP_A6.BIN ya está mapeada correctamente.&lt;br&gt;
Para las preguntas tenemos 4 opciones y para las respuestas otras 4 opciones por lo
que el número total de combinaciones queda reducido a 8. El único problema es que
la máquina tiene un generador de números aleatorios, por lo que si nos decantamos
por la opción de probar las 8 combinaciones distintas, tenemos que trucar el generador
de números aleatorios para que siempre estemos probando colocar las ROMs para la misma
pregunta.
&lt;/p&gt;
&lt;p&gt;
Tras 3 o 4 pruebas al fín obtenemos la combinación correcta:
&lt;/p&gt;
&lt;p&gt;
0x10000-0x13fff TP_A2.BIN&lt;br&gt;
0x14000-0x17fff TP_A7.BIN&lt;br&gt;
0x18000-0x1bfff TP_A4.BIN&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff TP_A8.BIN&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff TP_A6.BIN&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
Como para acertarla sin haber estudiado el juego a fondo...
&lt;/p&gt;
&lt;p&gt;
Aquí tenéis unas pantallas con el juego funcionando correctamente:
&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_008.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_009.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_010.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_011.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_012.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_013.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Le doy los últimos repasos al driver y lo envío a la lista del MAME.
&lt;/p&gt;
&lt;p&gt;
Espero que disfrutéis del juego muy pronto. Probablemente sea mi último driver para
el MAME.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
This is the third post about Trivial Pursuit Spanish. If you haven't read the previous
ones you can do it here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Last week we had the following ROM configuration:&lt;br&gt;
&amp;nbsp;0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
If we continue understanding code we reach the main loop of the game, where the code
jumps to a routine based on the current state. Here’s the method I’m talking about:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/mainloop.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
If we carefully study what happens in the state 0x04, where the game shows a question,
we finally found how the questions and answers are coded (routine at $f390). That
routine is large so I’m not going to show it but it’s curious to know how the questions
and answers were stored.
&lt;/p&gt;
&lt;p&gt;
A question is defined by 2 pointers. The first one is the start of the question and
the second one the core of the question. An example will explain this better than
me: The question: “Who was the first king that visited china?” has the first pointer
pointing to the sentence “Who” and the second one to “was the first king that visited
china”. Thanks to this schema they save a few bytes per question.
&lt;/p&gt;
&lt;p&gt;
This is only the first part as the characters for the sentences are coded in base
40. 3 characters are coded in 2 bytes. Again an example is the best to explain this:&lt;br&gt;
&amp;nbsp;&lt;br&gt;
If we have the following bytes:&lt;br&gt;
0x42 0x80 0x55 0x27&lt;br&gt;
&amp;nbsp;&lt;br&gt;
We take 2 bytes at a time and extract 3 base 40 digits so for 0x4280 we’ve got 10,
25 and 24 (0x0a, 0x19 and 0x18 in hexadecimal), and for 0x5527 we’ve got 13, 24 and
39 (0x0d, 0x18 and 0x27 in hexadecimal).
&lt;/p&gt;
&lt;p&gt;
After having the values, they’re sent to the routine we saw last week that printed
characters. That routine did the following conversion:&lt;br&gt;
0x00-0x09 -&amp;gt; numbers from 0 to 9&lt;br&gt;
0x0a-0x23 -&amp;gt; characters from 'a' to 'z'&lt;br&gt;
0x27-&amp;gt; space&lt;br&gt;
0x32-0x4b -&amp;gt; characters from 'A' to 'Z'
&lt;/p&gt;
&lt;p&gt;
If we check what we obtained previously:&lt;br&gt;
0x0a -&amp;gt; a, 0x19 -&amp;gt; p, 0x18 -&amp;gt; o, 0x0d -&amp;gt; d, 0x18 -&amp;gt; o, 0x27 -&amp;gt; space&lt;br&gt;
So the following bytes: 0x42 0x80 0x55 0x27 store "apodo " (spanish word for nickname).
&lt;/p&gt;
&lt;p&gt;
As the game stores the characters using base 40 codification, we can store only 40
characters, but the digits and lowercase letters make a total of 36 characters and
we are still missing punctuation marks, uppercase letters, etc. To solve that problem,
the game uses the value 0x24 as a marker to indicate that the character will be written
adding 0x28 to the next value. If we want to write Apodo instead of apodo we would
need the values:&lt;br&gt;
0x28 0x0a 0x19 0x18 0x0d 0x18
&lt;/p&gt;
&lt;p&gt;
With this information we can write a C# program that searchs all sentences in a ROM:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.IO;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Text;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; Trivial
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Program2&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;protected&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; ignorar;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; Main(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
args)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (args.Length
!= 2){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="COLOR: maroon"&gt;"Error,
se necesitan 2 argumentos: &amp;lt;rom&amp;gt; &amp;lt;salida.txt&amp;gt;"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; input
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[0]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; output
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StreamWriter&lt;/span&gt; writer
= output.CreateText();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileStream&lt;/span&gt; fileStream
= input.Open(&lt;span style="COLOR: teal"&gt;FileMode&lt;/span&gt;.Open);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt; br
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt;(fileStream);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
romData = br.ReadBytes(0x4000);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; br.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt; sb
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; i
= 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; startOffset
= 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
recorre la ROM grabando las frases que encuentre&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;while&lt;/span&gt; (i
&amp;lt; (0x4000 - 1)) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
0xff marca el fín de la frase, por lo que la escribe&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (romData[i]
== 0xff) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sb.Length
&amp;gt; 0) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(&lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Format(&lt;span style="COLOR: maroon"&gt;"{0:X}:
{1}"&lt;/span&gt;, startOffset, sb.ToString()));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Length = 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
i++;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
startOffset = i;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;continue&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
convierte 2 bytes en 3 digitos en base 40&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; num
= (romData[i] &amp;lt;&amp;lt; 8) | (romData[i + 1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
caracteres = CambioBase(num, 40, 3);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
escribe los dígitos&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; caracter &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; caracteres)
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
sb.Append(Convertir(caracter));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; i += 2;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(sb.ToString());
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// devuelve un array
de bytes con los dígitos del cambio de base&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
CambioBase(&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; valor, &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; baseNum, &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; numDigitos)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
resultado = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[numDigitos];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; pos
= numDigitos - 1;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;do&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; digito
= (&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;)(valor % baseNum);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; valor
= valor / baseNum;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; resultado[pos]
= digito;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; pos--;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="COLOR: blue"&gt;while&lt;/span&gt; (pos
&amp;gt;= 0);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; resultado;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// se encarga de
convertir un byte al código ASCII correspondiente&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; Convertir(&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; data)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; str
= &lt;span style="COLOR: maroon"&gt;"#"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
números&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x00) &amp;amp;&amp;amp; (data &amp;lt;= 0x09)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; str = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;((&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'0'&lt;/span&gt;)
+ (data - 0x00)), 1);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras minúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x0a) &amp;amp;&amp;amp; (data &amp;lt;= 0x23)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; str = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;((&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'a'&lt;/span&gt;)
+ (data - 0x0a)), 1);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
usado para convertir a mayúsculas o para poner acentos&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x24) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;""&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
espacio o fín de entrada&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x27) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (ignorar)
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;""&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="COLOR: blue"&gt;else&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
ignorar = &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;"
"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ignorar = &lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; str;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
If we run the program we get a lot of questions and answers in several ROMs: 
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
39a: nombre dieron los romanos a las islas canarias&lt;br&gt;
3bb: llamamos en espa#ol a la ciudad alemana de koln 
&lt;br&gt;
3de: de los ap3stoles alfab1ticamente es el primero&lt;br&gt;
3ff: lugar est0 #la creaci3n del hombre# de miguel angel 
&lt;br&gt;
426: de los evangelios cuenta que un ni#o le llev3 a jes4s 5 panes y 2 peces 
&lt;br&gt;
45b: dos paises hay cadenas monta#osas llamadas sierra nevada 
&lt;br&gt;
484: tienen como patr3n a san nicol0s&lt;br&gt;
49d: hero2na se abras3 en 1431&lt;br&gt;
4b0: continente no tiene ciudades capitales 
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
8FB: australiana&lt;br&gt;
904: ava gardner 
&lt;br&gt;
90F: sara montiel 
&lt;br&gt;
91A: gina lollobrigida 
&lt;br&gt;
929: brigitte bardot 
&lt;br&gt;
936: susana estrada 
&lt;br&gt;
943: arthur miller&lt;br&gt;
94E: hern0ndez mancha 
&lt;br&gt;
95D: john ford 
&lt;br&gt;
966: juan pablo ii 
&lt;br&gt;
973: ernesto iv 
&lt;/p&gt;
&lt;p&gt;
[...]
&lt;/p&gt;
&lt;p&gt;
So now we know what is inside the ROMs we don’t know how to map:&lt;br&gt;
TP_A2.BIN -&amp;gt; questions&lt;br&gt;
TP_A4.BIN -&amp;gt; answers&lt;br&gt;
TP_A6.BIN -&amp;gt; unknown data&lt;br&gt;
TP_A7.BIN -&amp;gt; questions and answers&lt;br&gt;
TP_A8.BIN -&amp;gt; questions and answers
&lt;/p&gt;
&lt;p&gt;
The same routine that decodes the questions and answers uses up to 4 different banks
to select a question, up to 4 different banks to select an answer and 2 banks to get
the pointers to the questions and answers, so thanks to that information we can map
ROM TP_A6.BIN and reduce the number of possible combinations to 8.
&lt;/p&gt;
&lt;p&gt;
After a few tries we finally found the proper combination:
&lt;/p&gt;
&lt;p&gt;
0x10000-0x13fff TP_A2.BIN&lt;br&gt;
0x14000-0x17fff TP_A7.BIN&lt;br&gt;
0x18000-0x1bfff TP_A4.BIN&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff TP_A8.BIN&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff TP_A6.BIN&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
Some screenshots of the game running:
&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_008.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_009.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_010.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_011.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_012.png" border=0&gt;&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_013.png" border=0&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
I’ll tidy up the code and send it to the MAMEDEV list.&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=658de6b6-4fae-48cc-bb0a-f5593cf336ac" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,658de6b6-4fae-48cc-bb0a-f5593cf336ac.aspx</comments>
      <category>Games</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=8e5e772a-5769-4741-b59a-d99a89e3e285</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8e5e772a-5769-4741-b59a-d99a89e3e285</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is first in Spanish and then in English.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Esta es la segunda noticia relacionada con el Trivial Pursuit en español. Si no has
leido la primera puedes hacerlo aquí:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</a>
        </p>
        <p>
Voy a comentar en detalle el proceso que he seguido para ir reduciendo las combinaciones.
Si no teneís conocimientos de arquitectura de computadores y ensamblador probablemente
mucho de lo siguiente os suene a chino, pero bueno, igual a alguien le interesa o
saca algo en claro... Si no os interesa, más abajo hay algunas fotos del juego.
</p>
        <p>
Lo primero a hacer es comparar las ROMs con las de otro trivial para ver las semejanzas.
Para ello el MAME trae una utilidad muy buena llamada ROMCMP. Comparando el trivial
en español con los distintos clones y siempre he obtenido los mismos resultados:
</p>
        <p>
          <img alt="romcmp.png" src="http://www.manuelabadia.com/blog/content/binary/romcmp.png" border="0" />
        </p>
        <p>
La ROM de sonido es similar, y 2 de las 3 de gráficos iguales. La otra es similar
en un 99.81% por lo que no hay ningún problema en mapear dichas ROMs. El problema
lo tenemos con las 8 de programa. Ninguna tiene una concordancia mayor del 10%, y
normalmente una concordancia tan baja es por tener muchos ceros o unos en alguna parte
de la ROM. Normalmente si la concordancia no es mayor del 70%, no podemos afirmar
nada, así que no partimos de nada a la hora de mapear las 8 ROMs de programa.
</p>
        <p>
He probado colocando las ROMs de programa en orden ascendente (de la TP_A1.BIN a la
TP_A8.BIN) y descendente pero no ha habido suerte. Por lo tanto, hay que buscar opciones
para reducir el número de combinaciones posibles (40320).
</p>
        <p>
El Trivial Pursuit usa como CPU principal un Motorola 6809 (CPU de 8 bits). Este procesador
al arrancar empieza a ejecutar instrucciones en la dirección apuntada por el vector
de reset, que está en 0xfffe-0xffff.
</p>
        <p>
Si observais el driver, el sistema utiliza bancos de 8 KB para ir paginando por las
ROMs, puesto que el espacio de direcciones de la CPU es de 64 KB y se necesita acceder
a 128 KB de datos. Por lo tanto el objetivo es encontrar una ROM que se mapee en el
rango de direcciones 0xe000-0xffff. Como cada ROM es de 0x4000 bytes, en cada ROM
hay 2 bancos, por lo que hay que observar la parte final de cada banco a ver si contienen
vectores válidos. No solo está el vector de reset, si no que hay varios como muestra
la siguiente tabla:
</p>
        <p>
FFF0H to FFF1H           |Reserved
by Motorola              
|<br />
FFF2H to FFF3H           |SWI3 instruction
interrupt vector  |<br />
FFF4H to FFF5H           |SWI2 instruction
interrupt vector  |<br />
FFF6H to FFF7H           |Fast hardware
int. vector (FIRQ)   |<br />
FFF8H to FFF9H           |Hardware
interrupt vector (IRQ)    |<br />
FFFAH to FFFBH           |SWI instruction
interrupt vector   |<br />
FFFCH to FFFDH           |Non-maskable
interrupt vector (NMI)|<br />
FFFEH to FFFFH           |Reset
vector                      
|
</p>
        <p>
A continuación muestro los últimos datos de cada posible banco de las ROMs asociadas
a la CPU. Si os habeis enterado de la parrafada anterior sería un buen ejercicio tratar
de adivinar que banco contiene el vector de arranque sin mirar la solución que está
después de la imagen.
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/romview1.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/romview2.png" border="0" />
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
Los datos no dan lugar a dudas. Los vectores están en el primer banco de la ROM A3:
</p>
        <p>
F382 F382 F382 FDA7 FBC6 F382 F382 F382
</p>
        <p>
En muchos juegos basados en el M6809 el vector de reset coincide con el del SWI, SWI2
y SWI3 como pasa en el trivial.
</p>
        <p>
Gracias a esto ya podemos mapear una ROM y tenemos la siguiente configuración:<br />
0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff ???<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff ???<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
Con lo que las combinaciones posibles pasan de 40320 a 5040.
</p>
        <p>
Como el trivial pursuit es un juego muy simple de programar, el código del programa
está todo en esta ROM por lo que si ejecutamos el juego poniendo cualquier combinación
en el resto de huecos ya podemos ver algo:
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_001.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_002.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_003.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_004.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border="0" />
                </td>
                <td>
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
Sin embargo, el resto de ROMs necesitan estar bien mapeadas para ver todos los gráficos
correctamente y sobre todo para que las preguntas y respuestas se muestren correctamente.
Al probar distintas combinaciones con el resto de ROMs se observa que los gráficos
de la presentación y del tablero van cambiando, por lo que tras unas pocas pruebas
se consigue ver la presentación y el tablero correctamente:
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_007.png" border="0" />
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
La ROM TP_A5.BIN contiene información sobre los gráficos del tablero y la TP_A1.BIN
información sobre los gráficos de la presentación. 
</p>
        <p>
De momento la configuración de las ROMs es:<br />
0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
Con lo que las combinaciones posibles pasan de 5040 a 120. No está mal para no haberse
metido a ver el código todavía.
</p>
        <p>
Si vamos probando unas cuantas combinaciones vemos que no hay manera de hacer que
las preguntas y las respuestas salgan bien, probablemente porque hay algún tipo de
dependencia entre las ROMs que impide ver nada a no ser que la combinación introducida
sea la correcta.
</p>
        <p>
Si podemos averiguar que es lo que contiene cada ROM que no sabemos mapear, tenemos
más puntos a nuestro favor para encontrar la combinación correcta. Si buscamos textos
en las ROMs no encontramos nada inteligible, por lo que estarán codificados de alguna
forma que no coincide con los caracteres ASCII (cosa que por otro lado tiene sentido,
ya que si se pueden ver las preguntas y las respuestas fácilmente sería facil piratear
el juego en otras plataformas puesto que la lógica del juego es mínima). 
</p>
        <p>
Por lo tanto, como no voy a probar las 120 combinaciones, no queda otra opción que
bucear en el ensamblador... La gran mayoría de juegos tienen al principio una serie
de comprobaciones de memoria y de ROMs (para comprobar que todo funciona bien) que
sirven para descubrir cómo se mapean las ROMs y en qué orden. Sin embargo, el trivial
tan solo tiene las comprobaciones de memoria y no las de las ROMs por lo que tan solo
nos queda ir entendiendo código hasta encontrar alguna rutina que nos oriente en la
colocación de las ROMs. Como he comentado antes, interesa saber que hay en cada ROM,
por lo que si vamos estudiando código, llegamos a la rutina que muestra por pantalla
el mensaje "Un momento por favor":
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/asm_frases.png" border="0" />
        </p>
        <p>
Esta rutina nos desvela que las frases se guardan de la siguiente forma:<br />
1 byte de color + 2 bytes de dirección en pantalla + n bytes de la frase (1 byte por
caracter) + 0xff (marcador de fín de frase)
</p>
        <p>
Cada caracter de la frase está codificado de la siguiente forma:
</p>
        <p>
0x00-0x09 -&gt; números del 0 al 9<br />
0x0a-0x23 -&gt; caracteres de la 'a' a la 'z'<br />
0x32-0x4b -&gt; caracteres de la 'A' a la 'Z'<br />
hay algunos caracteres más para símbolos de puntuación, acentos, eñes, etc que no
especifico, pero espero que capteis la idea.
</p>
        <p>
Me he creado un simple programa en C# al que le pasas una ROM y te busca todas las
frases posibles en este formato (no he tenido en cuenta acentos, eñes y demás): 
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Collections.Generic;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.IO;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Text;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">namespace</span> Trivial
</p>
          <p style="MARGIN: 0px">
{
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">class</span><span style="COLOR: teal">Program1</span></p>
          <p style="MARGIN: 0px">
    {
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">static</span><span style="COLOR: blue">void</span> oldMain(<span style="COLOR: blue">string</span>[]
args)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (args.Length
!= 2){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: teal">Console</span>.WriteLine(<span style="COLOR: maroon">"Error,
se necesitan 2 argumentos: &lt;rom&gt; &lt;salida.txt&gt;"</span>);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> input
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[0]);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> output
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[1]);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StreamWriter</span> writer
= output.CreateText();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileStream</span> fileStream
= input.Open(<span style="COLOR: teal">FileMode</span>.Open);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">BinaryReader</span> br
= <span style="COLOR: blue">new</span><span style="COLOR: teal">BinaryReader</span>(fileStream);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
romData = br.ReadBytes(0x4000);
</p>
          <p style="MARGIN: 0px">
            br.Close();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StringBuilder</span> sb
= <span style="COLOR: blue">new</span><span style="COLOR: teal">StringBuilder</span>();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
recorre la ROM grabando las frases que encuentre</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">for</span> (<span style="COLOR: blue">int</span> i
= 0; i &lt; 0x4000; i++) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
0xff marca el fín de la frase, por lo que la escribe</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (romData[i]
== 0xff) {
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">if</span> (sb.Length
&gt; 3) {
</p>
          <p style="MARGIN: 0px">
                   
    writer.WriteLine(<span style="COLOR: teal">String</span>.Format(<span style="COLOR: maroon">"{0:X}:
({1:X}, {2:X}{3:X}) -&gt; {4}"</span>, i - sb.Length, (<span style="COLOR: blue">int</span>)sb[0],
(<span style="COLOR: blue">int</span>)sb[1], (<span style="COLOR: blue">int</span>)sb[2],
sb.ToString(3, sb.Length - 3)));
</p>
          <p style="MARGIN: 0px">
                   
    sb.Length = 0;
</p>
          <p style="MARGIN: 0px">
                   
}
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">continue</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
añade caracteres a la frase</span></p>
          <p style="MARGIN: 0px">
                sb.Append(Convertir(romData[i]));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
            writer.WriteLine(sb.ToString());
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            writer.Close();
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// se encarga de
convertir un byte al código ASCII correspondiente</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">char</span> Convertir(<span style="COLOR: blue">byte</span> data)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
números</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x00) &amp;&amp; (data &lt;= 0x09)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'0'</span>)
+ (data - 0x00));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras minúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x0a) &amp;&amp; (data &lt;= 0x23)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'a'</span>)
+ (data - 0x0a));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
espacio</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x27) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span><span style="COLOR: maroon">'
'</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras mayúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x32) &amp;&amp; (data &lt;= 0x4b)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'A'</span>)
+ (data - 0x32));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span><span style="COLOR: maroon">'#'</span>;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
    }
</p>
          <p style="MARGIN: 0px">
}<br /><br /></p>
          <p style="MARGIN: 0px">
 
</p>
        </div>
        <p>
Desgraciadamente, las preguntas y respuestas del juego no están codificadas de esta
forma. Las frases que están codificadas de esta forma son:
</p>
        <p>
D21E: (23, 6E77) -&gt; Jugadores Magistrales<br />
D237: (23, 236F) -&gt;  Pulse Start 
<br />
D248: (23, 2323) -&gt; Creditos<br />
D254: (23, 2338) -&gt; Introduzca Moneda    
<br />
D26D: (23, 2323) -&gt; 1 Moneda 1 Juego<br />
D281: (23, 2323) -&gt; 2 Monedas 1 Juego<br />
D296: (23, 2323) -&gt; 2 Monedas 1 Juego<br />
D2AB: (23, 2323) -&gt; 1 Moneda 2 Juegos<br />
D2C0: (68, 4F23) -&gt; Juego Terminado<br />
D2D3: (68, 686F) -&gt; Usted est# entre los mejores<br />
D2F3: (68, 6D77) -&gt; C#ales son sus inicales<br />
D30E: (68, 206F) -&gt; Puntos<br />
D318: (23, 2323) -&gt; Muy bien Continue as#<br />
D331: (53, 2323) -&gt; Correcto o incorrecto 
<br />
D34B: (23, 3943) -&gt; Categor#a<br />
D358: (23, 6620) -&gt; Escenario y Pantalla<br />
D370: (23, 6623) -&gt; Gente y Recuerdos<br />
D386: (23, 6623) -&gt; Dias de Colegio<br />
D399: (30, 3030) -&gt; 0000<br />
D3A1: (23, 6623) -&gt; Ultimas Noticias<br />
D3B6: (23, 2323) -&gt; # 1987 Bally Sente<br />
D3CC: (42, 586B) -&gt; Lo siento la respuesta correcta es<br />
D3F2: (23, 2323) -&gt; La pr#xima vez lo sabr#<br />
D40D: (23, 2323) -&gt; Felicitaciones usted<br />
D425: (23, 4523) -&gt; es realmente un<br />
D438: (23, 4B76) -&gt; Maestro en Trivial Pursuit<br />
D456: (23, 4F73) -&gt; Su tiempo se ha acabado<br />
D471: (23, 2023) -&gt; Tiempo<br />
D47B: (23, 2333) -&gt; Baron Von Rightoften<br />
D493: (23, 237A) -&gt; Billie Genio 
<br />
D4A4: (23, 2351) -&gt; Cleopatra 
<br />
D4B2: (53, 2323) -&gt; Spartacus<br />
D4BF: (53, 2375) -&gt; Apriete Roja para cambiar de letra<br />
D4E5: (23, 2375) -&gt; Apriete Verde para fijar la letra<br />
D50A: (23, 2367) -&gt; Apriete Verde para elegir personaje<br />
D531: (53, 236B) -&gt; Apriete Rojo para cambiar<br />
D54E: (53, 236B) -&gt; al siguiente personaje<br />
D568: (23, 6E7A) -&gt; Seleccione su personaje<br />
D583: (53, 2375) -&gt; Apriete Rojo o Verde<br />
D59B: (23, 2323) -&gt; Juego gratis<br />
D5AB: (23, 6B23) -&gt;             
<br />
D5BB: (23, 7023) -&gt; Adaptacion del juego<br />
D5D3: (23, 7520) -&gt; y Software dise#o<br />
D5E8: (23, 4223) -&gt; Richard Adam<br />
D5F8: (23, 4723) -&gt; A#Anton Toca  
<br />
D60A: (23, 4C23) -&gt; J#Fernandez S# 
<br />
D61D: (23, 5723) -&gt;              
<br />
D62E: (23, 2342) -&gt;  MAIBESA 1987 
<br />
D640: (23, 2346) -&gt;      
<br />
D649: (53, 2323) -&gt;              
<br />
D65A: (23, 2323) -&gt; TRIVIAL PURSUIT   
<br />
D670: (23, 2323) -&gt; Volumen I I I         
<br />
D68A: (23, 237A) -&gt;                      
<br />
D6A3: (68, 6923) -&gt; Trivial Pursuit<br />
D6B6: (23, 5179) -&gt; Su puntuaci#n Magistral<br />
D6D1: (23, 5723) -&gt; es<br />
D6D7: (53, 2323) -&gt; Un momento por favor<br />
D6EF: (53, 2041) -&gt; Jugador<br />
D6FA: (23, 2345) -&gt; ARCADE
</p>
        <p>
y están todas en la ROM TP_A3.BIN, por lo que no hemos avanzado mucho en este sentido.
</p>
        <p>
He seguido desensamblando código hasta encontrar la rutina principal del juego, que
será la que nos desvele el misterio de cómo están codificadas las preguntas y las
respuestas, pero eso ya será en otro rato libre que pueda encontrar. La semana que
viene terminamos con la emulación del juego.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
This is the second post about Trivial Pursuit Spanish. If you haven't read the first
one you can do it here:
</p>
        <p>
          <a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx">http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</a>
        </p>
        <p>
I'm going to explain a little bit the process to reduce the number of possible combinations.
This will be a little technical but it may be interesting to somebody. If you're not
interested there're some screenshots below.
</p>
        <p>
The first thing to do its to compare the ROMs with other sets to spot similarities.
There is a pretty good utility that comes with MAME called ROMCMP that does this.
The results are:
</p>
        <p>
          <img alt="romcmp.png" src="http://www.manuelabadia.com/blog/content/binary/romcmp.png" border="0" />
        </p>
        <p>
The sound ROMs and graphic ROMs are similar so we now where to map them but the program
ROMs are completely different (10% of similarity or so isn’t significant. We need
at least 70% to consider them similar) so we don’t have a clue for mapping the program
ROMs.
</p>
        <p>
I tried in ascendant order (from TP_A1.BIN to TP_A8.BIN) and in descendant order but
the game doesn’t do anything, so we have to make something to reduce the total number
of combinations (40320).
</p>
        <p>
The game uses a Motorola 6809 (an 8 bit CPU) as the main CPU. This chip starts fetching
instructions from the reset vector located at 0xfffe-0xffff.
</p>
        <p>
If you look at the driver (balsente.c), the SAC-1 system uses 8 KB banks to handle
all ROM data, as the CPU can access to only 64 KB at a time and the ROMs have 128
KB of data. We need to find out which ROM maps to 0xe000-0xffff to start reverse engineering
code in order to reduce the number of combinations. As each ROM is 0x4000 bytes long,
we have 2 possible banks per ROM. We have to check the last bytes in each bank to
see if it has valid vectors that map in 0xe000-0xffff. The full vector table for the
M6809 is:
</p>
        <p>
FFF0H to FFF1H           |Reserved
by Motorola              
|<br />
FFF2H to FFF3H           |SWI3 instruction
interrupt vector  |<br />
FFF4H to FFF5H           |SWI2 instruction
interrupt vector  |<br />
FFF6H to FFF7H           |Fast hardware
int. vector (FIRQ)   |<br />
FFF8H to FFF9H           |Hardware
interrupt vector (IRQ)    |<br />
FFFAH to FFFBH           |SWI instruction
interrupt vector   |<br />
FFFCH to FFFDH           |Non-maskable
interrupt vector (NMI)|<br />
FFFEH to FFFFH           |Reset
vector                      
|
</p>
        <p>
I’m showing here the last bytes of each bank so you can try to identify them yourself
if you’re following me:
</p>
        <p>
Without a doubt the vectors are in the first bank of the ROM TP_A3.BIN:
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/romview1.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/romview2.png" border="0" />
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
F382 F382 F382 FDA7 FBC6 F382 F382 F382
</p>
        <p>
In a lot of games based on a M6809, the reset vector is the same as SWI, SWI2 and
SWI3 as happens with this game.
</p>
        <p>
Thanks to this we have one ROM mapped so for now we have:<br />
0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff ???<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff ???<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
So the possible number of combinations decreases from 40320 to 5040.
</p>
        <p>
As the game logic in this game is very simple, all the code is inside TP_A3.BIN so
if we run MAME now filling the unknown holes with a random combination we can see
something:
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_001.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_002.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_003.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_004.png" border="0" />
                </td>
              </tr>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border="0" />
                </td>
                <td>
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
Unfortunately some graphics and the questions and answers aren’t showing up properly
because we haven’t mapped them in the proper order. If you keep trying a few combinations
it’s easy to fix the splash screen and the board graphics. TP_A5.BIN has information
about the board and TP_A1.BIN about the splash screen:
</p>
        <p>
          <table>
            <tbody>
              <tr>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border="0" />
                </td>
                <td>
                  <img src="http://www.manuelabadia.com/blog/content/binary/triviaes_007.png" border="0" />
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <p>
So for now we have this ROM mapping configuration:<br />
0x10000-0x13fff ???<br />
0x14000-0x17fff ???<br />
0x18000-0x1bfff ???<br />
0x1c000-0x1ffff TP_A5.BIN<br />
0x20000-0x23fff ???<br />
0x24000-0x27fff TP_A1.BIN<br />
0x28000-0x2bfff ???<br />
0x2c000-0x2ffff TP_A3.BIN
</p>
        <p>
So now the possible combinations are reduced from 5040 to 120. Not bad if we consider
we haven’t studied a line of code!
</p>
        <p>
If we keep trying a few more combinations we realize that there’s no way to map the
other ROMs in order to see more progress (unless we were lucky enough to find the
proper combination).
</p>
        <p>
If we could know what kind of data is in each ROM it would be helpful to find the
correct mapping, so I searched for plain text in the ROM but found nothing, so they
coded the sentences somehow. So as I was in a dead end and I didn’t want to try 120
different combinations it was time to run the game with the debugger and understand
some code…
</p>
        <p>
Unfortunately in the power on self test there isn’t a ROM check as in a lot of games.
After some debugging you end up in the routine that writes a sentence to the video
memory (comments are in Spanish sorry):
</p>
        <p>
          <img src="http://www.manuelabadia.com/blog/content/binary/asm_frases.png" border="0" />
        </p>
        <p>
This routine shows how they coded this sentence in the ROM. The format is:<br />
1 byte for color + 2 bytes for destination address + n bytes of data (1 byte per character)
+ 0xff (end mark)
</p>
        <p>
Each character is coded this way:<br />
0x00-0x09 -&gt; numbers from ‘0’ to ‘9’<br />
0x0a-0x023 -&gt; characters from ‘a’ to ‘z’<br />
0x32-0x4b -&gt; characters from ‘A’ to ‘Z’<br />
There are more entries for for punctuation, accents, tilde, etc but you get the point…
</p>
        <p>
I wrote a simple C# program to find out all the sentences in a ROM to see if I could
find out what kind of data a ROM has:
</p>
        <div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Collections.Generic;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.IO;
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">using</span> System.Text;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">namespace</span> Trivial
</p>
          <p style="MARGIN: 0px">
{
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">class</span><span style="COLOR: teal">Program1</span></p>
          <p style="MARGIN: 0px">
    {
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">static</span><span style="COLOR: blue">void</span> oldMain(<span style="COLOR: blue">string</span>[]
args)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (args.Length
!= 2){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: teal">Console</span>.WriteLine(<span style="COLOR: maroon">"Error,
se necesitan 2 argumentos: &lt;rom&gt; &lt;salida.txt&gt;"</span>);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> input
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[0]);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileInfo</span> output
= <span style="COLOR: blue">new</span><span style="COLOR: teal">FileInfo</span>(args[1]);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StreamWriter</span> writer
= output.CreateText();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">FileStream</span> fileStream
= input.Open(<span style="COLOR: teal">FileMode</span>.Open);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">BinaryReader</span> br
= <span style="COLOR: blue">new</span><span style="COLOR: teal">BinaryReader</span>(fileStream);
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">byte</span>[]
romData = br.ReadBytes(0x4000);
</p>
          <p style="MARGIN: 0px">
            br.Close();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: teal">StringBuilder</span> sb
= <span style="COLOR: blue">new</span><span style="COLOR: teal">StringBuilder</span>();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
recorre la ROM grabando las frases que encuentre</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">for</span> (<span style="COLOR: blue">int</span> i
= 0; i &lt; 0x4000; i++) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
0xff marca el fín de la frase, por lo que la escribe</span></p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">if</span> (romData[i]
== 0xff) {
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">if</span> (sb.Length
&gt; 3) {
</p>
          <p style="MARGIN: 0px">
                   
    writer.WriteLine(<span style="COLOR: teal">String</span>.Format(<span style="COLOR: maroon">"{0:X}:
({1:X}, {2:X}{3:X}) -&gt; {4}"</span>, i - sb.Length, (<span style="COLOR: blue">int</span>)sb[0],
(<span style="COLOR: blue">int</span>)sb[1], (<span style="COLOR: blue">int</span>)sb[2],
sb.ToString(3, sb.Length - 3)));
</p>
          <p style="MARGIN: 0px">
                   
    sb.Length = 0;
</p>
          <p style="MARGIN: 0px">
                   
}
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                    <span style="COLOR: blue">continue</span>;
</p>
          <p style="MARGIN: 0px">
                }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//
añade caracteres a la frase</span></p>
          <p style="MARGIN: 0px">
                sb.Append(Convertir(romData[i]));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
            writer.WriteLine(sb.ToString());
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            writer.Close();
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">// se encarga de
convertir un byte al código ASCII correspondiente</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">private</span><span style="COLOR: blue">static</span><span style="COLOR: blue">char</span> Convertir(<span style="COLOR: blue">byte</span> data)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
números</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x00) &amp;&amp; (data &lt;= 0x09)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'0'</span>)
+ (data - 0x00));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras minúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x0a) &amp;&amp; (data &lt;= 0x23)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'a'</span>)
+ (data - 0x0a));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
espacio</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (data
== 0x27) {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span><span style="COLOR: maroon">'
'</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: green">//
letras mayúsculas</span></p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> ((data
&gt;= 0x32) &amp;&amp; (data &lt;= 0x4b)){
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">return</span> (<span style="COLOR: blue">char</span>)(((<span style="COLOR: blue">int</span>)<span style="COLOR: maroon">'A'</span>)
+ (data - 0x32));
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">return</span><span style="COLOR: maroon">'#'</span>;
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
    }
</p>
          <p style="MARGIN: 0px">
}<br /><br /></p>
          <p style="MARGIN: 0px">
 
</p>
        </div>
        <p>
Unfortunately the questions and answers aren’t coded this way, so the only readable
sentences I got were:<br />
 <br />
D21E: (23, 6E77) -&gt; Jugadores Magistrales<br />
D237: (23, 236F) -&gt;  Pulse Start 
<br />
D248: (23, 2323) -&gt; Creditos<br />
D254: (23, 2338) -&gt; Introduzca Moneda    
<br />
D26D: (23, 2323) -&gt; 1 Moneda 1 Juego<br />
D281: (23, 2323) -&gt; 2 Monedas 1 Juego<br />
D296: (23, 2323) -&gt; 2 Monedas 1 Juego<br />
D2AB: (23, 2323) -&gt; 1 Moneda 2 Juegos<br />
D2C0: (68, 4F23) -&gt; Juego Terminado<br />
D2D3: (68, 686F) -&gt; Usted est# entre los mejores<br />
D2F3: (68, 6D77) -&gt; C#ales son sus inicales<br />
D30E: (68, 206F) -&gt; Puntos<br />
D318: (23, 2323) -&gt; Muy bien Continue as#<br />
D331: (53, 2323) -&gt; Correcto o incorrecto 
<br />
D34B: (23, 3943) -&gt; Categor#a<br />
D358: (23, 6620) -&gt; Escenario y Pantalla<br />
D370: (23, 6623) -&gt; Gente y Recuerdos<br />
D386: (23, 6623) -&gt; Dias de Colegio<br />
D399: (30, 3030) -&gt; 0000<br />
D3A1: (23, 6623) -&gt; Ultimas Noticias<br />
D3B6: (23, 2323) -&gt; # 1987 Bally Sente<br />
D3CC: (42, 586B) -&gt; Lo siento la respuesta correcta es<br />
D3F2: (23, 2323) -&gt; La pr#xima vez lo sabr#<br />
D40D: (23, 2323) -&gt; Felicitaciones usted<br />
D425: (23, 4523) -&gt; es realmente un<br />
D438: (23, 4B76) -&gt; Maestro en Trivial Pursuit<br />
D456: (23, 4F73) -&gt; Su tiempo se ha acabado<br />
D471: (23, 2023) -&gt; Tiempo<br />
D47B: (23, 2333) -&gt; Baron Von Rightoften<br />
D493: (23, 237A) -&gt; Billie Genio 
<br />
D4A4: (23, 2351) -&gt; Cleopatra 
<br />
D4B2: (53, 2323) -&gt; Spartacus<br />
D4BF: (53, 2375) -&gt; Apriete Roja para cambiar de letra<br />
D4E5: (23, 2375) -&gt; Apriete Verde para fijar la letra<br />
D50A: (23, 2367) -&gt; Apriete Verde para elegir personaje<br />
D531: (53, 236B) -&gt; Apriete Rojo para cambiar<br />
D54E: (53, 236B) -&gt; al siguiente personaje<br />
D568: (23, 6E7A) -&gt; Seleccione su personaje<br />
D583: (53, 2375) -&gt; Apriete Rojo o Verde<br />
D59B: (23, 2323) -&gt; Juego gratis<br />
D5AB: (23, 6B23) -&gt;             
<br />
D5BB: (23, 7023) -&gt; Adaptacion del juego<br />
D5D3: (23, 7520) -&gt; y Software dise#o<br />
D5E8: (23, 4223) -&gt; Richard Adam<br />
D5F8: (23, 4723) -&gt; A#Anton Toca  
<br />
D60A: (23, 4C23) -&gt; J#Fernandez S# 
<br />
D61D: (23, 5723) -&gt;              
<br />
D62E: (23, 2342) -&gt;  MAIBESA 1987 
<br />
D640: (23, 2346) -&gt;      
<br />
D649: (53, 2323) -&gt;              
<br />
D65A: (23, 2323) -&gt; TRIVIAL PURSUIT   
<br />
D670: (23, 2323) -&gt; Volumen I I I         
<br />
D68A: (23, 237A) -&gt;                      
<br />
D6A3: (68, 6923) -&gt; Trivial Pursuit<br />
D6B6: (23, 5179) -&gt; Su puntuaci#n Magistral<br />
D6D1: (23, 5723) -&gt; es<br />
D6D7: (53, 2323) -&gt; Un momento por favor<br />
D6EF: (53, 2041) -&gt; Jugador<br />
D6FA: (23, 2345) -&gt; ARCADE
</p>
        <p>
And all were in ROM TP_A3.BIN so this didn’t help us very much.
</p>
        <p>
I continued debugging code until the main game loop, that will tell us all what we
need to know to emulate the game properly. However I ran out of time for this week
so until the next week I won’t be able to finish this game.
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=8e5e772a-5769-4741-b59a-d99a89e3e285" />
      </body>
      <title>MAME WIP - Trivial Pursuit (Spanish)</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</link>
      <pubDate>Sun, 05 Mar 2006 00:48:24 GMT</pubDate>
      <description>&lt;p&gt;
This post is&amp;nbsp;first in Spanish and then in English.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Esta es la segunda noticia relacionada con el Trivial Pursuit en español. Si no has
leido la primera puedes hacerlo aquí:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Voy a comentar en detalle el proceso que he seguido para ir reduciendo las combinaciones.
Si no teneís conocimientos de arquitectura de computadores y ensamblador probablemente
mucho de lo siguiente os suene a chino, pero bueno, igual a alguien le interesa o
saca algo en claro... Si no os interesa, más abajo hay algunas fotos del juego.
&lt;/p&gt;
&lt;p&gt;
Lo primero a hacer es comparar las ROMs con las de otro trivial para ver las semejanzas.
Para ello el MAME trae una utilidad muy buena llamada ROMCMP. Comparando el trivial
en español con los distintos clones y siempre he obtenido los mismos resultados:
&lt;/p&gt;
&lt;p&gt;
&lt;img alt=romcmp.png src="http://www.manuelabadia.com/blog/content/binary/romcmp.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
La ROM de sonido es similar, y 2 de las 3 de gráficos iguales. La otra es similar
en un 99.81% por lo que no hay ningún problema en mapear dichas ROMs. El problema
lo tenemos con las 8 de programa. Ninguna tiene una concordancia mayor del 10%, y
normalmente una concordancia tan baja es por tener muchos ceros o unos en alguna parte
de la ROM. Normalmente si la concordancia no es mayor del 70%, no podemos afirmar
nada, así que no partimos de nada a la hora de mapear las 8 ROMs de programa.
&lt;/p&gt;
&lt;p&gt;
He probado colocando las ROMs de programa en orden ascendente (de la TP_A1.BIN a la
TP_A8.BIN) y descendente pero no ha habido suerte. Por lo tanto, hay que buscar opciones
para reducir el número de combinaciones posibles (40320).
&lt;/p&gt;
&lt;p&gt;
El Trivial Pursuit usa como CPU principal un Motorola 6809 (CPU de 8 bits). Este procesador
al arrancar empieza a ejecutar instrucciones en la dirección apuntada por el vector
de reset, que está en 0xfffe-0xffff.
&lt;/p&gt;
&lt;p&gt;
Si observais el driver, el sistema utiliza bancos de 8 KB para ir paginando por las
ROMs, puesto que el espacio de direcciones de la CPU es de 64 KB y se necesita acceder
a 128 KB de datos. Por lo tanto el objetivo es encontrar una ROM que se mapee en el
rango de direcciones 0xe000-0xffff. Como cada ROM es de 0x4000 bytes, en cada ROM
hay 2 bancos, por lo que hay que observar la parte final de cada banco a ver si contienen
vectores válidos. No solo está el vector de reset, si no que hay varios como muestra
la siguiente tabla:
&lt;/p&gt;
&lt;p&gt;
FFF0H to FFF1H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Reserved
by Motorola&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
|&lt;br&gt;
FFF2H to FFF3H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI3 instruction
interrupt vector&amp;nbsp; |&lt;br&gt;
FFF4H to FFF5H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI2 instruction
interrupt vector&amp;nbsp; |&lt;br&gt;
FFF6H to FFF7H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Fast hardware
int. vector (FIRQ)&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFF8H to FFF9H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Hardware
interrupt vector (IRQ)&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFFAH to FFFBH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI instruction
interrupt vector&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFFCH to FFFDH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Non-maskable
interrupt vector (NMI)|&lt;br&gt;
FFFEH to FFFFH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Reset
vector&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
|
&lt;/p&gt;
&lt;p&gt;
A continuación muestro los últimos datos de cada posible banco de las ROMs asociadas
a la CPU. Si os habeis enterado de la parrafada anterior sería un buen ejercicio tratar
de adivinar que banco contiene el vector de arranque sin mirar la solución que está
después de la imagen.
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/romview1.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/romview2.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
Los datos no dan lugar a dudas. Los vectores están en el primer banco de la ROM A3:
&lt;/p&gt;
&lt;p&gt;
F382 F382 F382 FDA7 FBC6 F382 F382 F382
&lt;/p&gt;
&lt;p&gt;
En muchos juegos basados en el M6809 el vector de reset coincide con el del SWI, SWI2
y SWI3 como pasa en el trivial.
&lt;/p&gt;
&lt;p&gt;
Gracias a esto ya podemos mapear una ROM y tenemos la siguiente configuración:&lt;br&gt;
0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff ???&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff ???&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
Con lo que las combinaciones posibles pasan de 40320 a 5040.
&lt;/p&gt;
&lt;p&gt;
Como el trivial pursuit es un juego muy simple de programar, el código del programa
está todo en esta ROM por lo que si ejecutamos el juego poniendo cualquier combinación
en el resto de huecos ya podemos ver algo:
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_001.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_002.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_003.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_004.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
Sin embargo, el resto de ROMs necesitan estar bien mapeadas para ver todos los gráficos
correctamente y sobre todo para que las preguntas y respuestas se muestren correctamente.
Al probar distintas combinaciones con el resto de ROMs se observa que los gráficos
de la presentación y del tablero van cambiando, por lo que tras unas pocas pruebas
se consigue ver la presentación y el tablero correctamente:
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_007.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
La ROM TP_A5.BIN contiene información sobre los gráficos del tablero y la TP_A1.BIN
información sobre los gráficos de la presentación. 
&lt;/p&gt;
&lt;p&gt;
De momento la configuración de las ROMs es:&lt;br&gt;
0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
Con lo que las combinaciones posibles pasan de 5040 a 120. No está mal para no haberse
metido a ver el código todavía.
&lt;/p&gt;
&lt;p&gt;
Si vamos probando unas cuantas combinaciones vemos que no hay manera de hacer que
las preguntas y las respuestas salgan bien, probablemente porque hay algún tipo de
dependencia entre las ROMs que impide ver nada a no ser que la combinación introducida
sea la correcta.
&lt;/p&gt;
&lt;p&gt;
Si podemos averiguar que es lo que contiene cada ROM que no sabemos mapear, tenemos
más puntos a nuestro favor para encontrar la combinación correcta. Si buscamos textos
en las ROMs no encontramos nada inteligible, por lo que estarán codificados de alguna
forma que no coincide con los caracteres ASCII (cosa que por otro lado tiene sentido,
ya que si se pueden ver las preguntas y las respuestas fácilmente sería facil piratear
el juego en otras plataformas puesto que la lógica del juego es mínima). 
&lt;/p&gt;
&lt;p&gt;
Por lo tanto, como no voy a probar las 120 combinaciones, no queda otra opción que
bucear en el ensamblador... La gran mayoría de juegos tienen al principio una serie
de comprobaciones de memoria y de ROMs (para comprobar que todo funciona bien) que
sirven para descubrir cómo se mapean las ROMs y en qué orden. Sin embargo, el trivial
tan solo tiene las comprobaciones de memoria y no las de las ROMs por lo que tan solo
nos queda ir entendiendo código hasta encontrar alguna rutina que nos oriente en la
colocación de las ROMs. Como he comentado antes, interesa saber que hay en cada ROM,
por lo que si vamos estudiando código, llegamos a la rutina que muestra por pantalla
el mensaje "Un momento por favor":
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/asm_frases.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Esta rutina nos desvela que las frases se guardan de la siguiente forma:&lt;br&gt;
1 byte de color + 2 bytes de dirección en pantalla + n bytes de la frase (1 byte por
caracter) + 0xff (marcador de fín de frase)
&lt;/p&gt;
&lt;p&gt;
Cada caracter de la frase está codificado de la siguiente forma:
&lt;/p&gt;
&lt;p&gt;
0x00-0x09 -&amp;gt; números del 0 al 9&lt;br&gt;
0x0a-0x23 -&amp;gt; caracteres de la 'a' a la 'z'&lt;br&gt;
0x32-0x4b -&amp;gt; caracteres de la 'A' a la 'Z'&lt;br&gt;
hay algunos caracteres más para símbolos de puntuación, acentos, eñes, etc que no
especifico, pero espero que capteis la idea.
&lt;/p&gt;
&lt;p&gt;
Me he creado un simple programa en C# al que le pasas una ROM y te busca todas las
frases posibles en este formato (no he tenido en cuenta acentos, eñes y demás): 
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.IO;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Text;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; Trivial
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Program1&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; oldMain(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
args)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (args.Length
!= 2){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="COLOR: maroon"&gt;"Error,
se necesitan 2 argumentos: &amp;lt;rom&amp;gt; &amp;lt;salida.txt&amp;gt;"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; input
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[0]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; output
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StreamWriter&lt;/span&gt; writer
= output.CreateText();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileStream&lt;/span&gt; fileStream
= input.Open(&lt;span style="COLOR: teal"&gt;FileMode&lt;/span&gt;.Open);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt; br
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt;(fileStream);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
romData = br.ReadBytes(0x4000);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; br.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt; sb
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
recorre la ROM grabando las frases que encuentre&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;for&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; 0x4000; i++) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
0xff marca el fín de la frase, por lo que la escribe&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (romData[i]
== 0xff) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sb.Length
&amp;gt; 3) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(&lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Format(&lt;span style="COLOR: maroon"&gt;"{0:X}:
({1:X}, {2:X}{3:X}) -&amp;gt; {4}"&lt;/span&gt;, i - sb.Length, (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[0],
(&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[1], (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[2],
sb.ToString(3, sb.Length - 3)));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Length = 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;continue&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
añade caracteres a la frase&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(Convertir(romData[i]));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(sb.ToString());
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// se encarga de
convertir un byte al código ASCII correspondiente&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;char&lt;/span&gt; Convertir(&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; data)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
números&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x00) &amp;amp;&amp;amp; (data &amp;lt;= 0x09)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'0'&lt;/span&gt;)
+ (data - 0x00));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras minúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x0a) &amp;amp;&amp;amp; (data &amp;lt;= 0x23)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'a'&lt;/span&gt;)
+ (data - 0x0a));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
espacio&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x27) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;'
'&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras mayúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x32) &amp;amp;&amp;amp; (data &amp;lt;= 0x4b)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'A'&lt;/span&gt;)
+ (data - 0x32));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;'#'&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Desgraciadamente, las preguntas y respuestas del juego no están codificadas de esta
forma. Las frases que están codificadas de esta forma son:
&lt;/p&gt;
&lt;p&gt;
D21E: (23, 6E77) -&amp;gt; Jugadores Magistrales&lt;br&gt;
D237: (23, 236F) -&amp;gt;&amp;nbsp; Pulse Start 
&lt;br&gt;
D248: (23, 2323) -&amp;gt; Creditos&lt;br&gt;
D254: (23, 2338) -&amp;gt; Introduzca Moneda&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D26D: (23, 2323) -&amp;gt; 1 Moneda 1 Juego&lt;br&gt;
D281: (23, 2323) -&amp;gt; 2 Monedas 1 Juego&lt;br&gt;
D296: (23, 2323) -&amp;gt; 2 Monedas 1 Juego&lt;br&gt;
D2AB: (23, 2323) -&amp;gt; 1 Moneda 2 Juegos&lt;br&gt;
D2C0: (68, 4F23) -&amp;gt; Juego Terminado&lt;br&gt;
D2D3: (68, 686F) -&amp;gt; Usted est# entre los mejores&lt;br&gt;
D2F3: (68, 6D77) -&amp;gt; C#ales son sus inicales&lt;br&gt;
D30E: (68, 206F) -&amp;gt; Puntos&lt;br&gt;
D318: (23, 2323) -&amp;gt; Muy bien Continue as#&lt;br&gt;
D331: (53, 2323) -&amp;gt; Correcto o incorrecto 
&lt;br&gt;
D34B: (23, 3943) -&amp;gt; Categor#a&lt;br&gt;
D358: (23, 6620) -&amp;gt; Escenario y Pantalla&lt;br&gt;
D370: (23, 6623) -&amp;gt; Gente y Recuerdos&lt;br&gt;
D386: (23, 6623) -&amp;gt; Dias de Colegio&lt;br&gt;
D399: (30, 3030) -&amp;gt; 0000&lt;br&gt;
D3A1: (23, 6623) -&amp;gt; Ultimas Noticias&lt;br&gt;
D3B6: (23, 2323) -&amp;gt; # 1987 Bally Sente&lt;br&gt;
D3CC: (42, 586B) -&amp;gt; Lo siento la respuesta correcta es&lt;br&gt;
D3F2: (23, 2323) -&amp;gt; La pr#xima vez lo sabr#&lt;br&gt;
D40D: (23, 2323) -&amp;gt; Felicitaciones usted&lt;br&gt;
D425: (23, 4523) -&amp;gt; es realmente un&lt;br&gt;
D438: (23, 4B76) -&amp;gt; Maestro en Trivial Pursuit&lt;br&gt;
D456: (23, 4F73) -&amp;gt; Su tiempo se ha acabado&lt;br&gt;
D471: (23, 2023) -&amp;gt; Tiempo&lt;br&gt;
D47B: (23, 2333) -&amp;gt; Baron Von Rightoften&lt;br&gt;
D493: (23, 237A) -&amp;gt; Billie Genio 
&lt;br&gt;
D4A4: (23, 2351) -&amp;gt; Cleopatra 
&lt;br&gt;
D4B2: (53, 2323) -&amp;gt; Spartacus&lt;br&gt;
D4BF: (53, 2375) -&amp;gt; Apriete Roja para cambiar de letra&lt;br&gt;
D4E5: (23, 2375) -&amp;gt; Apriete Verde para fijar la letra&lt;br&gt;
D50A: (23, 2367) -&amp;gt; Apriete Verde para elegir personaje&lt;br&gt;
D531: (53, 236B) -&amp;gt; Apriete Rojo para cambiar&lt;br&gt;
D54E: (53, 236B) -&amp;gt; al siguiente personaje&lt;br&gt;
D568: (23, 6E7A) -&amp;gt; Seleccione su personaje&lt;br&gt;
D583: (53, 2375) -&amp;gt; Apriete Rojo o Verde&lt;br&gt;
D59B: (23, 2323) -&amp;gt; Juego gratis&lt;br&gt;
D5AB: (23, 6B23) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D5BB: (23, 7023) -&amp;gt; Adaptacion del juego&lt;br&gt;
D5D3: (23, 7520) -&amp;gt; y Software dise#o&lt;br&gt;
D5E8: (23, 4223) -&amp;gt; Richard Adam&lt;br&gt;
D5F8: (23, 4723) -&amp;gt; A#Anton Toca&amp;nbsp; 
&lt;br&gt;
D60A: (23, 4C23) -&amp;gt; J#Fernandez S# 
&lt;br&gt;
D61D: (23, 5723) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D62E: (23, 2342) -&amp;gt;&amp;nbsp; MAIBESA 1987 
&lt;br&gt;
D640: (23, 2346) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D649: (53, 2323) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D65A: (23, 2323) -&amp;gt; TRIVIAL PURSUIT&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D670: (23, 2323) -&amp;gt; Volumen I I I&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D68A: (23, 237A) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D6A3: (68, 6923) -&amp;gt; Trivial Pursuit&lt;br&gt;
D6B6: (23, 5179) -&amp;gt; Su puntuaci#n Magistral&lt;br&gt;
D6D1: (23, 5723) -&amp;gt; es&lt;br&gt;
D6D7: (53, 2323) -&amp;gt; Un momento por favor&lt;br&gt;
D6EF: (53, 2041) -&amp;gt; Jugador&lt;br&gt;
D6FA: (23, 2345) -&amp;gt; ARCADE
&lt;/p&gt;
&lt;p&gt;
y están todas en la ROM TP_A3.BIN, por lo que no hemos avanzado mucho en este sentido.
&lt;/p&gt;
&lt;p&gt;
He seguido desensamblando código hasta encontrar la rutina principal del juego, que
será la que nos desvele el misterio de cómo están codificadas las preguntas y las
respuestas, pero eso ya será en otro rato libre que pueda encontrar. La semana que
viene terminamos con la emulación del juego.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
This is the second post about Trivial Pursuit Spanish. If you haven't read the first
one you can do it here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx"&gt;http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
I'm going to explain a little bit the process to reduce the number of possible combinations.
This will be a little technical but it may be interesting to somebody. If you're not
interested there're some screenshots below.
&lt;/p&gt;
&lt;p&gt;
The first thing to do its to compare the ROMs with other sets to spot similarities.
There is a pretty good utility that comes with MAME called ROMCMP that does this.
The results are:
&lt;/p&gt;
&lt;p&gt;
&lt;img alt=romcmp.png src="http://www.manuelabadia.com/blog/content/binary/romcmp.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The sound ROMs and graphic ROMs are similar so we now where to map them but the program
ROMs are completely different (10% of similarity or so isn’t significant. We need
at least 70% to consider them similar) so we don’t have a clue for mapping the program
ROMs.
&lt;/p&gt;
&lt;p&gt;
I tried in ascendant order (from TP_A1.BIN to TP_A8.BIN) and in descendant order but
the game doesn’t do anything, so we have to make something to reduce the total number
of combinations (40320).
&lt;/p&gt;
&lt;p&gt;
The game uses a Motorola 6809 (an 8 bit CPU) as the main CPU. This chip starts fetching
instructions from the reset vector located at 0xfffe-0xffff.
&lt;/p&gt;
&lt;p&gt;
If you look at the driver (balsente.c), the SAC-1 system uses 8 KB banks to handle
all ROM data, as the CPU can access to only 64 KB at a time and the ROMs have 128
KB of data. We need to find out which ROM maps to 0xe000-0xffff to start reverse engineering
code in order to reduce the number of combinations. As each ROM is 0x4000 bytes long,
we have 2 possible banks per ROM. We have to check the last bytes in each bank to
see if it has valid vectors that map in 0xe000-0xffff. The full vector table for the
M6809 is:
&lt;/p&gt;
&lt;p&gt;
FFF0H to FFF1H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Reserved
by Motorola&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
|&lt;br&gt;
FFF2H to FFF3H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI3 instruction
interrupt vector&amp;nbsp; |&lt;br&gt;
FFF4H to FFF5H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI2 instruction
interrupt vector&amp;nbsp; |&lt;br&gt;
FFF6H to FFF7H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Fast hardware
int. vector (FIRQ)&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFF8H to FFF9H&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Hardware
interrupt vector (IRQ)&amp;nbsp;&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFFAH to FFFBH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |SWI instruction
interrupt vector&amp;nbsp;&amp;nbsp; |&lt;br&gt;
FFFCH to FFFDH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Non-maskable
interrupt vector (NMI)|&lt;br&gt;
FFFEH to FFFFH&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; |Reset
vector&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
|
&lt;/p&gt;
&lt;p&gt;
I’m showing here the last bytes of each bank so you can try to identify them yourself
if you’re following me:
&lt;/p&gt;
&lt;p&gt;
Without a doubt the vectors are in the first bank of the ROM TP_A3.BIN:
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/romview1.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/romview2.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
F382 F382 F382 FDA7 FBC6 F382 F382 F382
&lt;/p&gt;
&lt;p&gt;
In a lot of games based on a M6809, the reset vector is the same as SWI, SWI2 and
SWI3 as happens with this game.
&lt;/p&gt;
&lt;p&gt;
Thanks to this we have one ROM mapped so for now we have:&lt;br&gt;
0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff ???&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff ???&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
So the possible number of combinations decreases from 40320 to 5040.
&lt;/p&gt;
&lt;p&gt;
As the game logic in this game is very simple, all the code is inside TP_A3.BIN so
if we run MAME now filling the unknown holes with a random combination we can see
something:
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_001.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_002.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_003.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_004.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_005.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
Unfortunately some graphics and the questions and answers aren’t showing up properly
because we haven’t mapped them in the proper order. If you keep trying a few combinations
it’s easy to fix the splash screen and the board graphics. TP_A5.BIN has information
about the board and TP_A1.BIN about the splash screen:
&lt;/p&gt;
&lt;p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_006.png" border=0&gt; 
&lt;/td&gt;
&lt;td&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/triviaes_007.png" border=0&gt; 
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
So for now we have this ROM mapping configuration:&lt;br&gt;
0x10000-0x13fff ???&lt;br&gt;
0x14000-0x17fff ???&lt;br&gt;
0x18000-0x1bfff ???&lt;br&gt;
0x1c000-0x1ffff TP_A5.BIN&lt;br&gt;
0x20000-0x23fff ???&lt;br&gt;
0x24000-0x27fff TP_A1.BIN&lt;br&gt;
0x28000-0x2bfff ???&lt;br&gt;
0x2c000-0x2ffff TP_A3.BIN
&lt;/p&gt;
&lt;p&gt;
So now the possible combinations are reduced from 5040 to 120. Not bad if we consider
we haven’t studied a line of code!
&lt;/p&gt;
&lt;p&gt;
If we keep trying a few more combinations we realize that there’s no way to map the
other ROMs in order to see more progress (unless we were lucky enough to find the
proper combination).
&lt;/p&gt;
&lt;p&gt;
If we could know what kind of data is in each ROM it would be helpful to find the
correct mapping, so I searched for plain text in the ROM but found nothing, so they
coded the sentences somehow. So as I was in a dead end and I didn’t want to try 120
different combinations it was time to run the game with the debugger and understand
some code…
&lt;/p&gt;
&lt;p&gt;
Unfortunately in the power on self test there isn’t a ROM check as in a lot of games.
After some debugging you end up in the routine that writes a sentence to the video
memory (comments are in Spanish sorry):
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/asm_frases.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
This routine shows how they coded this sentence in the ROM. The format is:&lt;br&gt;
1 byte for color + 2 bytes for destination address + n bytes of data (1 byte per character)
+ 0xff (end mark)
&lt;/p&gt;
&lt;p&gt;
Each character is coded this way:&lt;br&gt;
0x00-0x09 -&amp;gt; numbers from ‘0’ to ‘9’&lt;br&gt;
0x0a-0x023 -&amp;gt; characters from ‘a’ to ‘z’&lt;br&gt;
0x32-0x4b -&amp;gt; characters from ‘A’ to ‘Z’&lt;br&gt;
There are more entries for for punctuation, accents, tilde, etc but you get the point…
&lt;/p&gt;
&lt;p&gt;
I wrote a simple C# program to find out all the sentences in a ROM to see if I could
find out what kind of data a ROM has:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.IO;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; System.Text;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;namespace&lt;/span&gt; Trivial
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Program1&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; oldMain(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
args)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (args.Length
!= 2){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="COLOR: maroon"&gt;"Error,
se necesitan 2 argumentos: &amp;lt;rom&amp;gt; &amp;lt;salida.txt&amp;gt;"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; input
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[0]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt; output
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;FileInfo&lt;/span&gt;(args[1]);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StreamWriter&lt;/span&gt; writer
= output.CreateText();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;FileStream&lt;/span&gt; fileStream
= input.Open(&lt;span style="COLOR: teal"&gt;FileMode&lt;/span&gt;.Open);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt; br
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;BinaryReader&lt;/span&gt;(fileStream);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[]
romData = br.ReadBytes(0x4000);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; br.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt; sb
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;StringBuilder&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
recorre la ROM grabando las frases que encuentre&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;for&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; 0x4000; i++) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
0xff marca el fín de la frase, por lo que la escribe&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (romData[i]
== 0xff) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sb.Length
&amp;gt; 3) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(&lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Format(&lt;span style="COLOR: maroon"&gt;"{0:X}:
({1:X}, {2:X}{3:X}) -&amp;gt; {4}"&lt;/span&gt;, i - sb.Length, (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[0],
(&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[1], (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)sb[2],
sb.ToString(3, sb.Length - 3)));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Length = 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;continue&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
añade caracteres a la frase&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(Convertir(romData[i]));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.WriteLine(sb.ToString());
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; writer.Close();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;// se encarga de
convertir un byte al código ASCII correspondiente&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;char&lt;/span&gt; Convertir(&lt;span style="COLOR: blue"&gt;byte&lt;/span&gt; data)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
números&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x00) &amp;amp;&amp;amp; (data &amp;lt;= 0x09)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'0'&lt;/span&gt;)
+ (data - 0x00));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras minúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x0a) &amp;amp;&amp;amp; (data &amp;lt;= 0x23)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'a'&lt;/span&gt;)
+ (data - 0x0a));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
espacio&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (data
== 0x27) {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;'
'&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//
letras mayúsculas&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; ((data
&amp;gt;= 0x32) &amp;amp;&amp;amp; (data &amp;lt;= 0x4b)){
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;char&lt;/span&gt;)(((&lt;span style="COLOR: blue"&gt;int&lt;/span&gt;)&lt;span style="COLOR: maroon"&gt;'A'&lt;/span&gt;)
+ (data - 0x32));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;'#'&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Unfortunately the questions and answers aren’t coded this way, so the only readable
sentences I got were:&lt;br&gt;
&amp;nbsp;&lt;br&gt;
D21E: (23, 6E77) -&amp;gt; Jugadores Magistrales&lt;br&gt;
D237: (23, 236F) -&amp;gt;&amp;nbsp; Pulse Start 
&lt;br&gt;
D248: (23, 2323) -&amp;gt; Creditos&lt;br&gt;
D254: (23, 2338) -&amp;gt; Introduzca Moneda&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D26D: (23, 2323) -&amp;gt; 1 Moneda 1 Juego&lt;br&gt;
D281: (23, 2323) -&amp;gt; 2 Monedas 1 Juego&lt;br&gt;
D296: (23, 2323) -&amp;gt; 2 Monedas 1 Juego&lt;br&gt;
D2AB: (23, 2323) -&amp;gt; 1 Moneda 2 Juegos&lt;br&gt;
D2C0: (68, 4F23) -&amp;gt; Juego Terminado&lt;br&gt;
D2D3: (68, 686F) -&amp;gt; Usted est# entre los mejores&lt;br&gt;
D2F3: (68, 6D77) -&amp;gt; C#ales son sus inicales&lt;br&gt;
D30E: (68, 206F) -&amp;gt; Puntos&lt;br&gt;
D318: (23, 2323) -&amp;gt; Muy bien Continue as#&lt;br&gt;
D331: (53, 2323) -&amp;gt; Correcto o incorrecto 
&lt;br&gt;
D34B: (23, 3943) -&amp;gt; Categor#a&lt;br&gt;
D358: (23, 6620) -&amp;gt; Escenario y Pantalla&lt;br&gt;
D370: (23, 6623) -&amp;gt; Gente y Recuerdos&lt;br&gt;
D386: (23, 6623) -&amp;gt; Dias de Colegio&lt;br&gt;
D399: (30, 3030) -&amp;gt; 0000&lt;br&gt;
D3A1: (23, 6623) -&amp;gt; Ultimas Noticias&lt;br&gt;
D3B6: (23, 2323) -&amp;gt; # 1987 Bally Sente&lt;br&gt;
D3CC: (42, 586B) -&amp;gt; Lo siento la respuesta correcta es&lt;br&gt;
D3F2: (23, 2323) -&amp;gt; La pr#xima vez lo sabr#&lt;br&gt;
D40D: (23, 2323) -&amp;gt; Felicitaciones usted&lt;br&gt;
D425: (23, 4523) -&amp;gt; es realmente un&lt;br&gt;
D438: (23, 4B76) -&amp;gt; Maestro en Trivial Pursuit&lt;br&gt;
D456: (23, 4F73) -&amp;gt; Su tiempo se ha acabado&lt;br&gt;
D471: (23, 2023) -&amp;gt; Tiempo&lt;br&gt;
D47B: (23, 2333) -&amp;gt; Baron Von Rightoften&lt;br&gt;
D493: (23, 237A) -&amp;gt; Billie Genio 
&lt;br&gt;
D4A4: (23, 2351) -&amp;gt; Cleopatra 
&lt;br&gt;
D4B2: (53, 2323) -&amp;gt; Spartacus&lt;br&gt;
D4BF: (53, 2375) -&amp;gt; Apriete Roja para cambiar de letra&lt;br&gt;
D4E5: (23, 2375) -&amp;gt; Apriete Verde para fijar la letra&lt;br&gt;
D50A: (23, 2367) -&amp;gt; Apriete Verde para elegir personaje&lt;br&gt;
D531: (53, 236B) -&amp;gt; Apriete Rojo para cambiar&lt;br&gt;
D54E: (53, 236B) -&amp;gt; al siguiente personaje&lt;br&gt;
D568: (23, 6E7A) -&amp;gt; Seleccione su personaje&lt;br&gt;
D583: (53, 2375) -&amp;gt; Apriete Rojo o Verde&lt;br&gt;
D59B: (23, 2323) -&amp;gt; Juego gratis&lt;br&gt;
D5AB: (23, 6B23) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D5BB: (23, 7023) -&amp;gt; Adaptacion del juego&lt;br&gt;
D5D3: (23, 7520) -&amp;gt; y Software dise#o&lt;br&gt;
D5E8: (23, 4223) -&amp;gt; Richard Adam&lt;br&gt;
D5F8: (23, 4723) -&amp;gt; A#Anton Toca&amp;nbsp; 
&lt;br&gt;
D60A: (23, 4C23) -&amp;gt; J#Fernandez S# 
&lt;br&gt;
D61D: (23, 5723) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D62E: (23, 2342) -&amp;gt;&amp;nbsp; MAIBESA 1987 
&lt;br&gt;
D640: (23, 2346) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D649: (53, 2323) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D65A: (23, 2323) -&amp;gt; TRIVIAL PURSUIT&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D670: (23, 2323) -&amp;gt; Volumen I I I&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D68A: (23, 237A) -&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
D6A3: (68, 6923) -&amp;gt; Trivial Pursuit&lt;br&gt;
D6B6: (23, 5179) -&amp;gt; Su puntuaci#n Magistral&lt;br&gt;
D6D1: (23, 5723) -&amp;gt; es&lt;br&gt;
D6D7: (53, 2323) -&amp;gt; Un momento por favor&lt;br&gt;
D6EF: (53, 2041) -&amp;gt; Jugador&lt;br&gt;
D6FA: (23, 2345) -&amp;gt; ARCADE
&lt;/p&gt;
&lt;p&gt;
And all were in ROM TP_A3.BIN so this didn’t help us very much.
&lt;/p&gt;
&lt;p&gt;
I continued debugging code until the main game loop, that will tell us all what we
need to know to emulate the game properly. However I ran out of time for this week
so until the next week I won’t be able to finish this game.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=8e5e772a-5769-4741-b59a-d99a89e3e285" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,8e5e772a-5769-4741-b59a-d99a89e3e285.aspx</comments>
      <category>Games</category>
    </item>
    <item>
      <trackback:ping>http://www.manuelabadia.com/blog/Trackback.aspx?guid=bce41855-2806-40e2-b956-e45ba07b3215</trackback:ping>
      <pingback:server>http://www.manuelabadia.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://www.manuelabadia.com/blog/CommentView,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</wfw:comment>
      <wfw:commentRss>http://www.manuelabadia.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=bce41855-2806-40e2-b956-e45ba07b3215</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This post is in Spanish and then in English.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
Tras muchos años de búsqueda, al fin he podido localizar una placa del Trivial Pursuit
en castellano (gracias José Manuel). Parece mentira que este juego haya sido tan difícil
de encontrar.
</p>
        <p>
Aquí tenéis una foto del juego en cuestión:
</p>
        <img src="http://www.manuelabadia.com/blog/content/binary/trivial_pcb.jpg" border="0" />
        <p>
 
</p>
        <p>
Se pueden observar 2 partes principales: las placas que forman el sistema Sente SAC-1
y el cartucho del juego. 
</p>
        <p>
Las placas que forman el sistema Sente SAC-1 son la de la CPU, que es la placa más
grande de la figura, y la de sonido, que está situada encima del cuadrante inferior
derecho de la placa de la CPU, así que cuesta un poco más verla.
</p>
        <p>
El cartucho del juego está a la derecha de las placas del sistema Sente SAC-1 y es
donde están las ROMs del juego. Si os fijáis bien podeis observar que hay 11 ROMs
en el cartucho. Las ROMs están etiquetadas como: TP_B4, TP_B5, TP_B6, TP_A1, TP_A2,
TP_A3, TP_A4, TP_A5, TP_A6, TP_A7 y TP_A8. Todas las ROMs son de 16 KB.
</p>
        <p>
Iré comentando un poco el proceso que sigo para conseguir tener el juego funcionando
por si tenéis curiosidad sobre estos procesos tan poco documentados. Sin embargo,
como el sistema sobre el que funciona el juego ya está emulado, la complejidad para
emular el juego disminuye bastante.
</p>
        <p>
Si observamos las ROMs de los otros trivials emulados de este sistema, podemos ver
que tienen o bien 6 ROMs de programa de 16 KB o bien 8 ROMs de programa de 8
KB, y todos tienen 3 ROMs de 16 KB (o bien 6 de 8 KB).
</p>
        <p>
Por lo tanto, pienso que las ROMs TP_B4, TP_B5 y TP_B6 serán los gráficos y el resto
de ROMs corresponderán al código. Probablemente tenga más ROMs que el resto de juegos
puesto que las frases en castellano suelen ocupar más que en inglés por lo que las
preguntas ocuparán más espacio. 
</p>
        <p>
Si observamos el driver del sistema Sente SAC-1 (balsente.c) comprobamos como cargan
las ROMs el resto de trivials (p.e. el triviasp):
</p>
        <p>
 ROM_LOAD( "allsport.8a", 0x10000, 0x4000, CRC(54b7ff31) )<br />
 ROM_LOAD( "allsport.7a", 0x14000, 0x4000, CRC(59fae9d2))<br />
 ROM_LOAD( "allsport.6a", 0x18000, 0x4000, CRC(237b6b95))<br />
 ROM_LOAD( "allsport.5a", 0x1c000, 0x4000, CRC(b64d7f61))<br />
 ROM_LOAD( "allsport.3a", 0x28000, 0x4000, CRC(e45d09d6))<br />
 ROM_LOAD( "allsport.1a", 0x2c000, 0x4000, CRC(8bb3e831))
</p>
        <p>
Se puede ver que los huecos 0x20000-0x23fff y 0x24000-0x27fff están vacíos. Como nuestro
juego tiene 8 ROMs de programa en vez de 6 no tendremos huecos, aunque la dificultad
reside en saber en que orden hay que poner las ROMs. Si habéis echado un vistazo al
driver, para el resto de trivials las ROMs se cargan en un orden lógico (de mayor
a menor o viceversa), así que con un poco de suerte, para la versión española las
ROMs se cargarán desde la TP_A1 a la TP_A8 o desde la TP_A8 a la TP_A1 sin dejar huecos.
</p>
        <p>
Si tuviéramos mala suerte y el juego no fuera un simple intercambio de ROMs pues tendríamos
que ponernos el mono de trabajo e investigar el código del programa para saber en
qué posición va cada ROM o bien probar todas las combinaciones. Como el número total
de combinaciones sería 8! = 8x7x6x5x4x3x2x1 = 40320, no es una opción viable tirar
por este camino si las ROMs no encajan tal cual.
</p>
        <p>
Como estoy muy liado, hasta este fin de semana no probaré nada de lo que os he comentado.
Conforme vaya haciendo algún progreso lo pondré en el blog.
</p>
        <p>
          <hr />
        </p>
        <p>
        </p>
        <p>
After a lot of searching, finally a Trivial Pursuit (Spanish) PCB has been found!
I was really scared about finding this one because if it was difficult to find some
Gaelco games that were very extended in Spain, this one could be lost for ever.
</p>
        <p>
Here’s a pic of the board:
</p>
        <img src="http://www.manuelabadia.com/blog/content/binary/trivial_pcb.jpg" border="0" />
        <p>
The cartdrige has the following ROMs: TP_B4, TP_B5, TP_B6, TP_A1, TP_A2, TP_A3, TP_A4,
TP_A5, TP_A6, TP_A7 and TP_A8 (all the ROMs are 16 KB).
</p>
        <p>
If we compare the other trivial games from the driver (balsente.c) we can see that
they have 6 program roms but this one has 8. This could be because english sentences
are usually shorter than Spanish ones so this one needs more room for questions.
</p>
        <p>
If we check how the ROMs are mapped in the driver the proper order is given by the
ROM labels either ascendant or descendant. If we’re lucky this one could fit that
schema and be a simple rom swap so we can get it working without getting dirty into
code. 
</p>
        <p>
However, if we don’t have luck there are 8! (40320) possible combinations for the
ROMs so we’ll need to study some code to reduce the combinations.
</p>
        <p>
As I’m busy now, I can’t look at it until the weekend.
</p>
        <p>
 
</p>
        <img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=bce41855-2806-40e2-b956-e45ba07b3215" />
      </body>
      <title>Trivial Pursuit Spanish - MAME Most Wanted PCB</title>
      <guid isPermaLink="false">http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</guid>
      <link>http://www.manuelabadia.com/blog/PermaLink,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</link>
      <pubDate>Wed, 01 Mar 2006 23:34:32 GMT</pubDate>
      <description>&lt;p&gt;
This post is in Spanish and then in English.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Tras muchos años de búsqueda, al fin he podido localizar una placa del Trivial Pursuit
en castellano (gracias José Manuel). Parece mentira que este juego haya sido tan difícil
de encontrar.
&lt;/p&gt;
&lt;p&gt;
Aquí tenéis una foto del juego en cuestión:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/trivial_pcb.jpg" border=0&gt; 
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Se pueden observar 2 partes principales: las placas que forman el sistema Sente SAC-1
y el cartucho del juego. 
&lt;/p&gt;
&lt;p&gt;
Las placas que forman el sistema Sente SAC-1 son la de la CPU, que es la placa más
grande de la figura, y la de sonido, que está situada encima del cuadrante inferior
derecho de la placa de la CPU, así que cuesta un poco más verla.
&lt;/p&gt;
&lt;p&gt;
El cartucho del juego está a la derecha de las placas del sistema Sente SAC-1 y es
donde están las ROMs del juego. Si os fijáis bien podeis observar que hay 11 ROMs
en el cartucho. Las ROMs están etiquetadas como: TP_B4, TP_B5, TP_B6, TP_A1, TP_A2,
TP_A3, TP_A4, TP_A5, TP_A6, TP_A7 y TP_A8. Todas las ROMs son de&amp;nbsp;16 KB.
&lt;/p&gt;
&lt;p&gt;
Iré comentando un poco el proceso que sigo para conseguir tener el juego funcionando
por si tenéis curiosidad sobre estos procesos tan poco documentados. Sin embargo,
como el sistema sobre el que funciona el juego ya está emulado, la complejidad para
emular el juego disminuye bastante.
&lt;/p&gt;
&lt;p&gt;
Si observamos las ROMs de los otros trivials emulados de este sistema, podemos ver
que tienen o bien 6 ROMs de programa de 16&amp;nbsp;KB o bien 8 ROMs de programa de&amp;nbsp;8
KB, y todos tienen 3 ROMs de&amp;nbsp;16 KB (o bien 6 de&amp;nbsp;8 KB).
&lt;/p&gt;
&lt;p&gt;
Por lo tanto, pienso que las ROMs TP_B4, TP_B5 y TP_B6 serán los gráficos y el resto
de ROMs corresponderán al código. Probablemente tenga más ROMs que el resto de juegos
puesto que las frases en castellano suelen ocupar más que en inglés por lo que las
preguntas ocuparán más espacio. 
&lt;/p&gt;
&lt;p&gt;
Si observamos el driver del sistema Sente SAC-1 (balsente.c) comprobamos como cargan
las ROMs el resto de trivials (p.e. el triviasp):
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;ROM_LOAD( "allsport.8a", 0x10000, 0x4000, CRC(54b7ff31) )&lt;br&gt;
&amp;nbsp;ROM_LOAD( "allsport.7a", 0x14000, 0x4000, CRC(59fae9d2))&lt;br&gt;
&amp;nbsp;ROM_LOAD( "allsport.6a", 0x18000, 0x4000, CRC(237b6b95))&lt;br&gt;
&amp;nbsp;ROM_LOAD( "allsport.5a", 0x1c000, 0x4000, CRC(b64d7f61))&lt;br&gt;
&amp;nbsp;ROM_LOAD( "allsport.3a", 0x28000, 0x4000, CRC(e45d09d6))&lt;br&gt;
&amp;nbsp;ROM_LOAD( "allsport.1a", 0x2c000, 0x4000, CRC(8bb3e831))
&lt;/p&gt;
&lt;p&gt;
Se puede ver que los huecos 0x20000-0x23fff y 0x24000-0x27fff están vacíos. Como nuestro
juego tiene 8 ROMs de programa en vez de 6 no tendremos huecos, aunque la dificultad
reside en saber en que orden hay que poner las ROMs. Si habéis echado un vistazo al
driver, para el resto de trivials las ROMs se cargan en un orden lógico (de mayor
a menor o viceversa), así que con un poco de suerte, para la versión española las
ROMs se cargarán desde la TP_A1 a la TP_A8 o desde la TP_A8 a la TP_A1 sin dejar huecos.
&lt;/p&gt;
&lt;p&gt;
Si tuviéramos mala suerte y el juego no fuera un simple intercambio de ROMs pues tendríamos
que ponernos el mono de trabajo e investigar el código del programa para saber en
qué posición va cada ROM o bien probar todas las combinaciones. Como el número total
de combinaciones sería 8! = 8x7x6x5x4x3x2x1 = 40320, no es una opción viable tirar
por este camino si las ROMs no encajan tal cual.
&lt;/p&gt;
&lt;p&gt;
Como estoy muy liado, hasta este fin de semana no probaré nada de lo que os he comentado.
Conforme vaya haciendo algún progreso lo pondré en el blog.
&lt;/p&gt;
&lt;p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
After a lot of searching, finally a Trivial Pursuit (Spanish) PCB has been found!
I was really scared about finding this one because if it was difficult to find some
Gaelco games that were very extended in Spain, this one could be lost for ever.
&lt;/p&gt;
&lt;p&gt;
Here’s a pic of the board:
&lt;/p&gt;
&lt;img src="http://www.manuelabadia.com/blog/content/binary/trivial_pcb.jpg" border=0&gt; 
&lt;p&gt;
The cartdrige has the following ROMs: TP_B4, TP_B5, TP_B6, TP_A1, TP_A2, TP_A3, TP_A4,
TP_A5, TP_A6, TP_A7 and TP_A8 (all the ROMs are&amp;nbsp;16 KB).
&lt;/p&gt;
&lt;p&gt;
If we compare the other trivial games from the driver (balsente.c) we can see that
they have 6 program roms but this one has 8. This could be because english sentences
are usually shorter than Spanish ones so this one needs more room for questions.
&lt;/p&gt;
&lt;p&gt;
If we check how the ROMs are mapped in the driver the proper order is given by the
ROM labels either ascendant or descendant. If we’re lucky this one could fit that
schema and be a simple rom swap so we can get it working without getting dirty into
code. 
&lt;/p&gt;
&lt;p&gt;
However, if we don’t have luck there are 8! (40320) possible combinations for the
ROMs so we’ll need to study some code to reduce the combinations.
&lt;/p&gt;
&lt;p&gt;
As I’m busy now, I can’t look at it until the weekend.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.manuelabadia.com/blog/aggbug.ashx?id=bce41855-2806-40e2-b956-e45ba07b3215" /&gt;</description>
      <comments>http://www.manuelabadia.com/blog/CommentView,guid,bce41855-2806-40e2-b956-e45ba07b3215.aspx</comments>
      <category>Games</category>
    </item>
  </channel>
</rss>