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.
- 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?
- 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
- 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
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.
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>
Dos meses despues de iniciada esta aventura, tengo grabada en una EPROM un programa que de ejecutarse se manifestaría en GPIO.
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 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.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.4 T0 A14 P2.6 -> N/C
- P3.5 T1 A13 P2.5 -> N/C
- P3.6 WR A12 P2.4 -> 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 - 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
P0.1 -> 2D L 7D <- P0.6
<- 2Q S 7Q ->
<- 3Q 3 6Q ->
<- 3Q 3 6Q ->
P0.2 -> 3D 7 6D <- P0.5
P0.3 -> 4D 3 5D <- P0.4
<- 4Q 5Q ->
<- 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
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
+------------------+
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
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
+------------------+
P0.1 <- D1 M D5 -> P0.5
P0.2 <- D2 D4 -> P0.4
GND - GND D3 -> P0.3
+------------------+
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
Si mi programa estuviera funcionando el patrón de PORT0 debería ser algo así como
0
1
2
3
4
5
1
2
3
4
5
6
2
3
....
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...
Resumen
Pasos
- 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
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.