Veníamos de reemplazar algunos switches y leds por VIO.
Llegó el momento de hacer que este juguete sea más productivo, para eso hace falta poder ingresar hashes arbitrarios en pocos segundos o menos en lugar de regenerar el bitstream en decenas de minutos.
La idea es eliminar el selector de hashes hardcodeados e ingresar el hash a buscar de alguna manera. Sería bastante complicado hacerlo físicamente, habría que conectar 128 switches o ir cargando por tandas, demasiado trabajo y muy fácil equivocarse al cargar.
Pero, ¿qué son 128 switches virtuales, que además entienden hexadecimal? Gracias a VIO puedo ahorrarme la interfaz de usuario.
Aunque mucho mejor que la opción física, para probar muchos valores es un tanto tedioso, luego exploraré interactuar programáticamente con el VIO y así poder testear no una simulación sino la realidad misma.
Primero lo primero, el VIO manual.
VIO total |
Hay que quitar los selectores y enchufarle el VIO a la entrada de los hashes.
Para modificar el VIO hay que hacerle doble click al xci:
Seleccionar el xci |
Y ajustar los nuevos valores:
Nueva probe, fijate como me equivoqué con ese 127 |
También hay que cambiar la interfaz del driver tambien, antes entraban cuatro bits, ahora son 128 en su lugar.
Los assign para que VIO muestre nombres útiles:
wire [ 4 : 0] probe_in0;
wire [ 31 : 0] probe_in1;
wire [ 4 : 0] probe_out0;
wire [ 127 : 0] probe_out1;
assign probe_in0 = {
status_paused,
status_running,
status_warming,
status_found,
status_done
};
assign probe_out0 = enable_switch;
assign probe_in1 = target;
assign probe_out1 = target_selected;
La nueva interfaz del VIO:
vio_0 vio_driver (
.clk(CLK), // input wire clk
.probe_in0(probe_in0), // input wire [4 : 0] probe_in0
.probe_in1(probe_in1), // input wire [31 : 0] probe_in1
.probe_out0(probe_out0),// output wire [0 : 0] probe_out0
.probe_out1(probe_out1) // output wire [127 : 0] probe_out0
);
Recordá que es output respecto al VIO, va a un input del diseño.
La nueva interfaz del driver:
driver u_driver(
.CLK (CLK),
.CPU_RESETN (CPU_RESETN),
.enable_switch (enable_switch),
.target_selected(target_selected),
.target (target),
.status_paused (status_paused),
.status_running (status_running),
.status_warming (status_warming),
.status_found (status_found),
.status_done (status_done)
);
Hasta acá parecía fácil, pero cuando estaba corrigiendo el ancho de VIO se cerró Vivado y aunque luego lo corregí y parecía todo ok, de modo efectivo quedó de 127 bits en lugar de 128. O mejor dicho, aceptó el assign probe_out1 = target_selected pero lo tomó de 127 bits y me dejó uno aparte, si hubiera sido el más significativo pude haber lidiado pero al ser el menos significativo rompe toda la representación hexadecimal.
Tuve que pedirle "Regenerate Output Products" en Design Runs pero los tomó de la cache:
Cached |
Tiré la IP y volvíendolo a incorporar nuevamente me ignoró hasta que encontré como limpiar la cache, en particular vía GUI:
- Project manager
- Settings
- IP
- IP Cache
- Clear Cache
Y...
no, falló.
Pensé que era por el assign, lo quité.
Tiré todo el proyecto salvo los .v y el xpr
Partí el probe en dos de 64 bits...
Ok, anda, hora de ver el manual. Virtual Input/Output v3.0 LogiCORE IP Product Guide (PG 159) no es, sólo explica el IP, obvio, el problema está en Vivado logic analyzer, cuya documentación en un framentito de Vivado Design Suite User Guide: Programming and Debugging (UG 908) desde la página 205, no veo nada que indique esa limitación.
Como sea, debido a ese error del comienzo, no sé si Vivado quedó "contaminado" o justo accidentalmente hay una limitación o bug que impide manipular un probe de 128 bits.
Quedó todo muy parecido a lo expuesto anteriormente, salvo que en lugar de un probe de 128 bits tengo dos de 64, no me quita el sueño.
wire [ 4 : 0] probe_in0;
wire [31 : 0] probe_in1;
wire [ 4 : 0] probe_out0;
wire [ 63 : 0] probe_out1;
wire [ 63 : 0] probe_out2;
vio_0 vio_driver (
.clk(CLK), // input wire clk
.probe_in0(probe_in0), // input wire [4 : 0] probe_in0
.probe_in1(probe_in1), // input wire [31 : 0] probe_in1
.probe_out0(probe_out0), // output wire [0 : 0] probe_out0
.probe_out1(probe_out1), // output wire [63 : 0] probe_out1
.probe_out2(probe_out2) // output wire [63 : 0] probe_out2
);
driver u_driver(
.CLK (CLK),
.CPU_RESETN (CPU_RESETN),
.enable_switch (enable_switch),
.target_selected({probe_out1,probe_out2}),
.target (target),
.status_paused (status_paused),
.status_running (status_running),
.status_warming (status_warming),
.status_found (status_found),
.status_done (status_done)
);
Veamos la secuencia completa de un reset por placa, cargar el hash en el VIO, ejecución y hallazgo.
Reset, el circuito está en modo "paused", target en cero.
reset |
Tras ingresar en la consola tcl los comandos:
set_property OUTPUT_VALUE d96ff7938f84d310 [get_hw_probes probe_out1 -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
commit_hw_vio [get_hw_probes {probe_out1} -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
set_property OUTPUT_VALUE c9d25805bfdbabb2 [get_hw_probes probe_out2 -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
commit_hw_vio [get_hw_probes {probe_out2} -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
queda el valor del hash en probe_out1 y probe_out2:
hash cargado |
Al oprimir en VIO enable_switch, pasa al estado "running" tras un efímero "warming":
buscando |
Como halla el valor, queda en "done" y "found":
hallado |
Fijate que el valor es el esperado "BEBA_CAFE" + 0x220, pronto lidiaremos con ello.
El código en github
Notas relacionadas
- Basic Digital Design EAMTA 2021
- Refactorizaciones de MD5 en FPGA: 1 simulación
- Refactorizaciones de MD5 en FPGA: 2 VIO
- Refactorizaciones de MD5 en FPGA: 3 VIO total
- Refactorizaciones de MD5 en FPGA: 4 algunos arreglitos
No hay comentarios:
Publicar un comentario