2020/05/31

Rescatando un 8051


O de como pasar la cuarentena.

En los primeros días de Octubre de 2019, anticipando #quedateencasa en general y #QuedateEnCasaYReverseateAlgo en particular, mientras elaboraba los contenidos de "Método de entrenamiento de (de)soldado" y "Para estudiar Hardware Security" y sentando las bases para "EDU-CIAA-NXP-SEG", necesitaba soldar para ésta última un lpc43s37 de reemplazo, pero mis torpes manos no estaban a la altura de la tarea, así que me propuse fabricarme algún tipo de herramienta.

Para construir esa herramienta necesitaba elementos, repartidos en decenas de cajones, cajitas, bolsas, o sea, el quilombo habitual.

Me puse a ordenar y tras varias semanas de trabajo lo logré, pasé de tener una pocilga a un quirófano y de paso (re)encontré esto, que hace años había perdido de vista:





Es la controladora de un disco rígido muy viejo, probablemente ESDI. Lo que me interesa es la CPU, que en realidad es un microcontrolador, esto es una CPU con varios periféricos en el mismo chip. Entiendo que fué y quizás sigue siendo un chip muy estimado en los cursos introductorios de programación de microcontroladores en varias universidades.







Leyendo en varias sitios llegué a este conocimiento:

  • Tiene una PROM, esto es Programmable ROM.
  • Es WORM (Write Once, Read Many), sólo se puede programar una vez.
  • Pero alguien dijo que una vez programado se puede reusar arrancando de una ROM externa.

Probablemente mi proyecto sea viable:

  • Aplicaré el enunciado del capítulo 4 de Hardware Security que consiste en identificar los componentes. Esto no es del todo necesario pero quiero cruzar la hoja de datos con lo que tenga conectado como para practicar.
  • Desoldaré todo lo que pueda, para practicar tambien (en realidad este fué el primer paso, pero debió haber sido el segundo...)
  • Asumiré que no está rota.
  • Haré la conexión eléctrica mínima tal que funcione.
  • Pondré un blinky en una EEPROM o similar.
  • Andará y eso es todo, me daré por satisfecho.
Puede ser que no llegue a hacer todo, ya sea por:
  • Falta de habilidad
  • Destrucción prematura del 8051
  • Imposibilidad real de ejecutar código externo

 

 Las preguntas


¿Me atreveré a intentar hacerla andar a partir de las especificaciones o buscaré, estoy seguro que tengo, algún apunte que heredé de algún estudiante de electrónica donde explica cómo hacerlo? Especificaciones y google, en alguna limpieza me deshice de los apuntes o los dejé muy bien escondidos.

¿Programaré una eeprom o intentaré algún hack como el del increiblemente inspirante artículo Emulación de ROM de Quinn BlondiHacks?

¿Seré capaz de darme cuenta si he llegado a un punto muerto? ¿Seré capaz de rendirme?

Lo que pensé que sería un proyecto relativamente corto resultó ser una pesadilla de ramificaciones directas que me llevó a escribir:

  • https://seguridad-agile.blogspot.com/2020/04/generador-precario-de-senales-cuadradas.html
  • https://seguridad-agile.blogspot.com/2020/04/diagnosticando-avrdude-usbasp-arduino.html
  • https://seguridad-agile.blogspot.com/2020/05/programando-eprom-con-atmega328p.html
E indirectas por oportunidad, estuve adquiriendo o completando conocimientos para terminar cosas a medio hacer:

  • https://seguridad-agile.blogspot.com/2020/04/twister-del-azar.html
  • https://seguridad-agile.blogspot.com/2020/04/adaptacion-de-los-microcontroladores.html
  • https://seguridad-agile.blogspot.com/2020/04/metodos-para-identificar-el-pinout-de.html

Manos a la obra, al final hay un resumen por si te resulta muy tedioso leer todo esto.

Desoldado


Nada especial, aire caliente a 390 °C del otro lado y la cosita que aspira.

Reconocimiento

No sé donde dejé la placa de donde saqué el chip, así que no voy a poder ver a qué estaba conectado y no voy a disponer del cristal original por que lo saqué hace años.

Mientras, viendo http://www.cpu-world.com/CPUs/8051/Intel-P8051AH.html y la datasheet entiendo que:



  • RAM
    • 128 B internal, me interesa
    • va de 0x00H a 0x7F
    • de 0x00 a 0x1F están mapeados los registros R0–R7
    • de 0x80 de 0xFF Registros especiales
    • 64 KB external, no me interesa
  • ROM
    • 4 KB internal, inútil
    • 60 KB external, me interesa 0000H a FFFFH

Pinout


VCC y VSS: para la alimentación.

RST: High para reset.

ALE/~PROG: emite a 1/6 de la frecuencia del oscilador, me servirá como control.

EA (External Access): debe estar a tierra para que use la memoria de programa externa. Si el security bit está activo, estoy afuera, no va a accederla.

~PSEN para el enable de la lectura de memoria externa, me interesa.

XTAL1 y XTAL2: acá va el cristal y unos capacitores que bastante me hicieron sufrir.

PORT0 se usa para acceder al programa externo, tiene multiplexado la parte baja de la dirección y el bus de datos. Esto me va a complicar horriblemente la vida.

PORT1 parece ok para los leds.

PORT2 se usa para acceder al programa externo, la parte alta de las direcciones.

PORT3 se usa para la memoria externa que no me interesa, podría usarlo.

Acción


Primer paso, el clock.


Conecté en un protoboard la alimentación, el cristal y los capacitores que canibalicé, es difícil un lunes feriado de cuarentena conseguir nada.




Medí en XTAL1 y ALE y aunque las formas son horribles, las frecuencias están bien, fijate que 1.6 (cyan) x 6 = 9.6 (amarillo), entiendo que puedo seguir.




 


Primer paso, segundo intento.


Basándome en https://www.electroschematics.com/at89s52-minimum-development-board-8051-tutorial-2/, puse algunas conexiones más a ver si se manifiesta en mejores curvitas y voy arrimando a lo que hay que llegar de todos modos. No hubo diferencia, así que me mudé a un PCB preperforado o como se llame, perdiendo en el camino el cristal de 9.6, lo reemplacé por uno de 8.


Los zócalos de la izquierda no están en uso, pero observá que uno está poblado


Fijate que las cuentas se mantienen ok, pero como invertí las puntas los colores están al revés.




Lo que no me gusta es que arrancó consumiendo 1.84A y luego bajó a .8A, lo cual está muy mal pues dice consumir 250 mA, espero que no esté frito. Igual tengo esperanzas, al ponerle RST a tierra bajó, veremos.

Me imagino que el comportamiento que estoy viendo no indica que el microcontrolador esté funcionando, sólo el clock.

Segundo paso, las direcciones externas.

Para ver si hay vida, ahora le voy a pedir que use la ROM externa y espero encontrar alguna actividad digital en las pistas, vamos por EA.



Recordemos, hay que poner EA a tierra.



Tras mucho sufrir:
  • ¿Viste que había algo en uno de los zócalos supuestamente vacíos? Era un 74LS374 del próximo paso que por los cambios del trazado del PCB estaba con la polaridad invertida, de ahí los 0.8 A, ahora estamos con 70 mA.
  • El 8051 tiende a soltarse del zócalo.
  • Tuve que poner las resistencia a positivo del PORT0
  • No recordaba en absoluto como usar el analizador de protocolos.
Hay señales de vida:




A esas transiciones no les veo un patrón claro, pero sin duda son demasiado regulares, puede ser que esté en coma, pero no muerto.


sigrok-cli  -d fx2lafw:conn=5.6 --time 3000 -o dump.vcd -O vcd

# prender y apagar el microcontrolador

gtkwave dump.vcd



Luego ví en el man sigrok-cli que existe pulseview que tiene decoders y puede usar al analizador lógico directamente, pero es menos usable, no tiene para avanzar y retroceder buscando la próxima transición ni para medir intervalos.




Con el decoder de paralelo podemos ver los valores hexadecimales del PORT0


Lo tengo instalado vía los repositorios de la distro, con versión 0.2, en su repo va por la 0.4, es muy tentador pero antes voy a intentar usar el formato nativo de sigrok y sus opciones de docoder a ver si me quedo con gtkwave.

Nop, no incluye el decoding.

Ahora bien, si lo que se está ejecutando es un programa, cada vez que arranca debería producir la misma traza.

Tras bastante probar y reflexionar y hacer cosas como ejecutar dos veces esto con distintos archivos de salida:

sigrok-cli  -d fx2lafw --time 3000 --config "samplerate=24 MHz" \
    --triggers 0=1,1=1,2=1,3=1,4=1,5=1,6=1,7=1 --wait-trigger\
    -O vcd -o dumpDec24.1.vcd



Aunque podemos ver patrones repetitivos, los comienzos son distintos así que me imagino que estoy encarando mal.

Por un lado, estoy mirando PORT0 con programa externo que implica que va a multiplexar escritura de dirección con lectura de código y eso no debe ser bueno para un principiante como yo.

Voy a mirar PORT2 que dice sólo emitir la direcciones altas y yo apostaría que debe estar todo en cero, veamos.



Perfecto, acá claramente se vé un patrón que parece corresponder a estar barriendo todo el espacio de memoria en 100 ms, si miramos las capturas anteriores el ciclo completo debería durar 100 / 256 = 0.4 us,


Al comienzo en el pin 7 (cero en el chip) hay un poco de basura, distinta en ambos pero el resto es idéntico.




Segundo paso emprolijado

No he prestado mucha atención a que los pines del chip correspondan a los canales y llegó el momento de correlacionar, así que tomaré los cuatro más altos de los bajos (PORT0 4 a 7) y los cuatro más bajos de los altos (PORT2 0 a 3).




Perfecto, ahora, tras examinar las lineas de control ALE y PSEN en relación a varios, llegué a esta captura:




Los dos primeros canales son ALE y PSEN, el tercero es A8 en PORT2, los restantes AD7, AD3, AD2, AD1 y AD0 (Siendo A Address y D Data) de  PORT0

Se nota claramente como influye ALE sobre los canales de PORT0, le hace meter esos niveles positivos por los pullups cuando esta low, cosa que no ocurre con A8 de PORT2, recordemos que siguiendo la danza de ALE y PSEN esas mismas líneas se utilizan para leer de la ROM tras haber puesto la dirección.

Para comprender los tiempos, me hice una planillita que calcula los valores variables, en este caso para 8 Mhz




Las fórmulas por si te sirven

Combinando la tabla con el siguiente gráfico, hay que comprender como funciona.



No es muy intuitivo, pero gtkwave te deja medir un intervalo haciendo click y arrastrando.



Midiendo TAVLL


Luego registro todos los valores, notando que algunos están dados por el hardware actual y los otros son los que habrán que respetar.





Lo que queda es calcular algo tal que se respete todo lo amarillo...


...o mucho mejor aun, meter sin más reflexión directamente el 74LS373  con el opcode de NOP, total acá no dice que haya que tomar ningun precaución extra.


Tercer paso, nop

Siguiendo la idea de Quinn ya citada, con estas instrucciones lo que pensaba intentar hacer es que ante cualquier pedido de instrucción aparezca un NOP en el bus de datos, para eso hace falta un 74LS373 y tengo un 74LS374, cuya única diferencia es esta:

que parece ser que lo que tengo sólo tomará el cambio en el flanco positivo del reloj provisto por ALE. Esto puede ser un problema pues según lo visto previamente, o quizás algo de lo anterior está mal analizado.


Pero el NOP no se va a manifestar más que lo que está haciendo ahora, está leyendo FF:





Está simplemente pasando a la instrucción siguiente, me conviene ya pasar al siguiente paso para despejarme.

Instalé mcu8051ide que es muy bonito y tiene un simulador al cual incluso se le pueden pegar unos leds.

Éste es el código que necesito, inicializa PORT1 (0x90, 144) en vano (malinterpreté en ese momento, el yo del futuro que revisa lo escrito sabe que debí haberlo inicializado en cero pero luego me hubiera complicado la escritura del al PROM), luego pone un 1 en el registro A, el cual copia a PORT1, le hace un shift con carry, un nop y salta al loop.


A la izquierda el código assembly, a la derecha el de máquina.






Me voy a quedar con una versión más corta,

     mov A,#254
loop:
     mov 144, A
     rlc A
     sjmp loop


(74 FE F5 90 33 80 FB)

pues con tres bits de direccionamiento alcanza para servirlo en lugar de cuatro bits.

Ahora tengo que ver como usando los tres bits más bajos sirvo esa secuencia, tengo que implementar un emulador de memoria de 8 direcciones.

La verdad es que ya estoy bastante conforme con lo que he logrado y aprendido hasta ahora, todo parece indicar que el chip está vivo, el bit de protección no está activado y si le pusiera una ROM la ejecutaría. Me frustraría mucho quemar todo al tratar de hacer la conexión que falta. Lo que hizo Quinn me sirve de inspiración, pero es demasiado, no quiero cargar programas arbitrarios y cuando dice "ROM emulator" no es lo que las palabras me sugieren, es una RAM a la cual su CPU no puede escribir pero ella sí con gran ingenio.

Alguna noche mientras transitaba esta experiencia tuve una epifanía, en realidad mi "ROM emulator" ni siquiera necesita decodificar las direcciones, alcanza con que entregue la siguiente secuencia:

74 FE F5 90 33 80 FB F5 90 33 80 FB F5 90 33 80 FB ....


Así que voy a meditar dos implementaciones de ROM emulator, una que decodifique la dirección pedida y en función de esta entregue un código y otra que sólo detecte que es momento de mandar la próxima instrucción.

Mi dificultad en este momento pasa por la electrónica, no quemar nada.







Habiendo descansado, noto que me estoy salteando un paso: poner el 74LS374 y ver si obtengo la señal de PORT0 limpia. No la obtengo y me ha costado entender.

Tal como había anticipado, la diferencia entre 74LS374 y 74LS374 me está afectando. Tengo varios 74LS374, y podría canibalizar varios maś, pero ningún 74LS373, debe ser por que todo lo que tengo proviene de sistemas con clock.

La situación es que le pulso ascendente de ALE no me sirve.

Para arreglarlo se me ocurre esto usan una señal de alta frecuencia y hacer AND con ALE para que vaya actualizandose el buffer.


Pero no tengo como generar señales, ¿o si?

Un 555


Esto es puro robo, tengo que buscar un diagrama en Internet y si tengo las resistencia y capacitores apropiados, tendré mi señal. Y si los 555 que tengo generan esa frecuencia, lo dudo, ni me voy a fijar.

Un timer de otro microcontrolador


Mirándo rápido, para el LPC4337 de la edu-ciaa-nxp quizás tendría, pero nuevamente me estaría copiando, es un tema interesante... para otra ocasión.

Una FPGA


¿Para qué llevo meses/años practicando Verilog? Y como puede ser que me equivoque y queme algo, ¿qué mejor que usar el iCEstick? , así de paso aprendo a usar el entorno de Lattice.

Me voy a hacer un rústico generador de ondas cuadradas lo que sin duda me desvía del tema 8051, pero bueno, la idea era aprender todo lo posible en el camino, no?

<desvío>

Para programar necesito usar Lattice iCEcube2 que tengo instalado en una máquina virtual con una licencia que venció en el 2018, luego, hacer el programa, hacer la adaptación eléctrica de 3.3v de la FPGA a los 5 del 8051 y finalmente probar a ver si anda todo ok.

Como es muy largo y como dije más arriba es un desvío, que además tiene subdesvíos, lo vas a tener que leer en otra entrada y luego volver.


https://es.wikipedia.org/wiki/Archivo:Turnout_components.jpg


</desvío>


Recapitulando, he puesto la señal ALE con un AND a 12Mhz, de modo tal que se generen pulsos para el clock del 74ls374 y tome el valor de la dirección en el momento apropiado en lugar de en el flanco ascendente de ALE.






Que con el analizar lógico se ve mejor:




Observá que a veces hay uno y uno, tres y dos pulsos en la tercera linea que es 12Mhz AND ALE debe tener que ver con la baja calidad de lo que he hecho, la falta de conocimiento mía de electrónica analógica.

Poniéndo un inversor 74ls14 entre 12Mhz y el AND mejora mucho.




Ahora siempre hay tres pulsos

El siguiente paso es ver si se fué el multiplexado del PORT0 a la salida del 74ls374... no, tras tomar el siguiente desvío y sufrir la estructura fractal de este proyecto, me compré un 74ls373 para no tener que lidiar con esto, buen intento, olvidemos la FPGA, la adaptación de niveles y todo eso y...

<desvío>

... concentrémonos en grabar el programa en la EPROM.

</desvío>

Dos meses despues de iniciada esta aventura, tengo grabada en una EPROM un programa que de ejecutarse se manifestaría en GPIO.


Address? (xxxx): 0010
Size? (xxxx): 0040
Reading address from: 0010 to : 0050
0010  40  31  EA  40  D3  01  DB  05 
0018  24  22  52  05  3E  40  D3  01 
0020  1E  00  18  17  FF  FF  FF  FF 
0028  10  10  11  10  11  00  FB  11 
0030  74  FE  F5  90  33  80  FB  FF 
0038  C3  4E  01  D3  1E  D3  1A  10 
0040  63  D3  10  3E  49  D3  11  10 
0048  45  D3  12  3E  97  D3  13  3E

esto siginifica que tengo mi programa en la dirección 0030 cuando debería estar en 0000, voy a tener que manipular físicamente las direcciones.


Esto deseo, en negrita lo direccionable por la eprom:

0000 0000 0000 0000

Esto tengo:

0000 0000 0011 0000



Este es el circuito




Mi programa sólo necesita las tres últimas líneas, resto irá puenteado directamente a 0 o 1.


            +---------------------------+
           <- P1.0                 Vcc  - 5v
           <- P1.1             A0 P0.0 <-> 1D
           <- P1.2        I    A1 P0.1 <-> 2D
           <- P1.3        N    A2 P0.2 <-> 3D
           <- P1.4        T    A3 P0.3 <-> 4D
           <- P1.5        E    A4 P0.4 <-> 5D
           <- P1.6        L    A5 P0.5 <-> 6D
           <- P1.7             A6 P0.6 <-> 7D
            - RST         8    A7 P0.7 <-> 8D
            - P3.0  RXD   0         EA  - GND
            - P3.1  TXD   5        ALE  ->
            - P3.2  INT0  1       PSEN  -> OE/CE
            - P3.3  INT1      A15 P2.7  -> N/C
            - P3.4  T0        A14 P2.6  -> N/C
            - P3.5  T1        A13 P2.5  -> N/C
            - P3.6  WR        A12 P2.4  -> N/C
            - P3.7  RD        A12 P2.3  -> N/C
       xtal - XTAL2           A10 P2.2  -> N/C
       xtal - XTAL1            A9 P2.1  -> N/C
        GND - Vss              A8 P2.0  -> N/C
            +---------------------------+



                +------------------+
            GND -> OC         Vcc  - 5v
               <- 1Q     7     8Q  ->
          P0.0  -> 1D    4     8D <- P0.7
          P0.1  -> 2D    L     7D <- P0.6
               <-  2Q    S     7Q  ->
               <-  3Q    3     6Q  ->
          P0.2  -> 3D    7     6D <- P0.5
          P0.3  -> 4D    3     5D <- P0.4
               <- 4Q           5Q  ->
                -  GND         C  <- ALE
                +-----------------+


                 +------------------+
            GND  -> A7         Vcc  - 5v
            GND  -> A6    2     A8 <- GND
            GND  -> A5    K     A9 <- GND
             5v  -> A4    B    Vpp  - Vcc
             5v  -> A3          OE <- PSEN
             3Q  -> A2    E    A10 <- GND
             2Q  -> A1    P     CE <- PSEN
             1Q  -> A0    R     D7  -> P0.7
           P0.0 <-  D0    O     D6  -> P0.6
           P0.1 <-  D1    M     D5  -> P0.5
           P0.2 <-  D2          D4  -> P0.4
            GND  -  GND         D3  -> P0.3
                 +------------------+



Así sería si quisiera acceder a toda la EPROM:

                 +------------------+
             8Q  -> A7         Vcc  - 5v
             7Q  -> A6    2     A8 <- P2.0
             6Q  -> A5    K     A9 <- P2.1
             5Q  -> A4    B    Vpp  - Vcc
             4Q  -> A3          OE <- PSEN
             3Q  -> A2    E    A10 <- P2.2
             2Q  -> A1    P     CE <- PSEN
             1Q  -> A0    R     D7  -> P0.7
           P0.0 <-  D0    O     D6  -> P0.6
           P0.1 <-  D1    M     D5  -> P0.5
           P0.2 <-  D2          D4  -> P0.4
            GND  -  GND         D3  -> P0.3
                 +------------------+





Las últimas desventuras





Habiendo soldado todo, comprobado visualmente y cortos y continuidad con el tester, se me desoldado uno de los capacitores y no lo encuentro.

Rescato los SMD de la placa original y cuando estoy por soldar... se me sale volando uno y no lo encuentro.

Cuando estoy desoldando los de la placa de la central telefónica, se deprende una patita.... lo arreglo.

Conecto mirando PORT1, ruido...



A diagnosticar...


El comportamiento en el bus de direcciones no ha cambiado, apuesto a que mi programa no se activó.

Me parece que no configuré correctamente PORT1 como output, pero aún así, al menos en un bit debería tener actividad y no la hay.

Esto está respaldado por lo que se vé en PORT1, se parece a modo input.

Si mi programa estuviera funcionando el patrón de PORT0 debería ser algo así como

0
1
2
3
4
5
6
2
3
....

con los valores de las instrucciones intercaladas y no lo es.



Por un lado, si en realidad es posible, estoy muy cerca de finalizarlo, por el otro, ya aprendí un montón de cosas, estoy cansado y me estoy atrasando en otras mil cosas que quiero hacer. De un modo u otro, debo asumir mi derrota...

Quizás dentro de unas semanas o meses me inspire e investigue otra vez, por ahora, ya está.

Resumen


Pasos


Cambiando levemente el orden:

  • Extraje el chip
  • Identifiqué los pines y sus funciones
  • Le puse un cristal para ver si funcionaba el clock con el osciloscopio
  • Configuré para que use ROM externa
  • Miré si había actividad en el bus de direcciones con un analizador lógico
  • Estudié el timing del multiplexado de datos y direcciones en PORT0
  • Puse un 74ls374 para demultiplexar
  • Recuperé el uso de iCEcube2 y VHDL
  • Escribí un VHDL para generar una señal por la falta de 74ls373
  • Puse un 74ls373
  • Asumí que el demultiplexado está ocurriendo correctamente
  • Aprendí a leer y grabar EPROM con un microcontrolador
  • Escribí un programa de 8051
  • Lo grabé
  • Armé la placa
  • Fallé


Recursos utilizados


Algunos no son de esta entrada si no de las derivadas, enumero para mostrar todo lo que implica una investigación sencilla como esta.


Herramientas

  • Soldador
  • Multímetro
  • Fuente
  • Osciloscopio
  • Analizador lógico
  • USBasp


Hardware

  • Protoboard
  • PCB de desarrollo
  • 74ls374
  • 74ls373
  • 74hc164
  • 14008
  • iCEstick
  • cristal quarzo 8Mhz (tras perder el de 9.6Mhz)
  • cablecitos, resistencias, pines, zócalo, capacitores, transistores, rele


Software

  • dia
  • Lattice iCEcube2
  • MCU 8051 IDE
  • recordmydesktop --x=400 --y=1800 --width=900 --height=700 --no-sound
  • pulseview
  • gtkwave
  • sigrok-cli
  • avrdude
  • arduino-ide
  • virtualbox
  • gimp
  • libreoffice calc

Documentación



Algunos artículos de Quinn los leí hace mucho y ahora apenas el pasé una mirada por encima, asi que los pasos quizás no sean los mismos. Pero sin duda es el origen de esta experiencia, lo que me inspiró a tomar este camino.