En los últimos días estábamos solucionando la conversión entre el bus de datos y direcciones de las memorias y del tester. En abstracto éste es un problema resoluble de forma óptima mediante redes de permutaciones de bits (Beneš), un terreno muy trillado en criptografía pero como la realidad es muy tozuda había que comprobar en la práctica los resultados en un Nano. La función con la red de permutación de bits para el bus de direcciones de la 4116 daba buenos tiempos, calcular la asociada a una fila o una columna de una memoria llevaba en promedio unos 14µs o, lo que es lo mismo, 224 ciclos de reloj del Nano. Cada operación de direccionamiento implica direccionar una fila, una columna, manipular /RAS, /CAS, /WE... por lo que, si se puede, mejor evitar el lujo de invertir los 28µs/448ciclos en las permutaciones.
Modelizando ambos buses encontramos que para el de direcciones hay tres tipos diferentes, el de la 41464, el de la 41256 y el de la 44256; y para el de datos son también tres tipos y coinciden con las mismas memorias. Si utilizamos tablas
lookup para las permutaciones de los buses de direccionamiento y datos se requieren unos 3942 bytes, bastante más de los exiguos 2048 bytes de la SRAM del Nano, pero si en lugar de generar en RAM las estrictamente necesarias (de 816 o 1542 bytes según la memoria) antes de las operaciones, por ejemplo, durante la espera en la pantalla de cableado, van registradas como constantes en el propio programa es viable alojar esos 3942 bytes en los 32768 de la memoria de programa. No tenemos otra opción puesto que en las pruebas con la tabla
lookup en RAM para la 4116 teníamos un tiempo de "cálculo" promedio de 0µs (por debajo de la precisión de la medida en microsegundos, o sea, <1µs o <16 ciclos) frente a los 14µs del cálculo sobre la marcha.
La parte simpática apareció cuando nos topamos con un curioso
bug del compilador de Arduino IDE. Supongamos que ejecutamos éste simple y sucio código en nuestro Nano:
Código: Seleccionar todo
typedef struct
{
byte array1[3];
byte array2[4];
} myStruct;
const static myStruct data[2] PROGMEM = {
{
{9, 8, 7},
{1, 2, 3, 4}
},
{
{10, 11, 12},
{6, 7, 8, 9}
}
};
void setup()
{
Serial.begin( 115200 );
Serial.print( " [ " );
for ( byte bA = 0; bA < 3; bA++ )
{
Serial.print( data[0].array1[bA] );
Serial.print( " " );
}
Serial.println( "]" );
Serial.print( " [ " );
for ( byte bB = 0; bB < 3; bB++ )
{
Serial.print( data[1].array2[bB] );
Serial.print( " " );
}
Serial.println( "]" );
}
void loop()
{
}
obtendríamos en el puerto serie la siguiente salida, tal y como cabía esperar:
pero si modificamos donde dice "bB < 3" por "bB < 4" para que en lugar de mostrar 3 elementos muestre 4, la salida es:
o cualquier burrada parecida, muy fácil de resolver con un programa tan pequeño (de menos de 160 bytes) pero que ha molestado en las pruebas reales con un programa de más de 16kB en el que el objeto que gestiona la pantalla se lleva nada más arrancar el 25% de la RAM disponible.