Este es el detalle del trabajo práctico de la materia Micro Arquitecturas y Soft Cores, ya comentada previamente.
El objetivo es instanciar el Forzador Brutal de MD5 en un chip ZYNQ de una placa PYNQ-Z2 proveniente de una Nexys4DDR que es más grande, ya habiendo fracasado durante la cursada de Basic Digital Design agregando VIO e ILA como interfaz. En esta oportunidad la interfaz será AXI hacia los cores donde se ejecutará un programita escrito en C.
Pasos
Necesito saber previamente algunos datos:
Número de registros para el periférico AXI
- para determinar el hash (input, 128 bits, 16 bytes, 4 registers )
- para obtener el valor (output, 32 bits, 4 bytes, 1 register)
- control para iniciar proceso (input, 1 bit, 1 register)
- status (output 3 bits, 1 register)
- running
- found
- done
Son 7 registros.
Respecto a estos pasos, tengo un fuerte Déjà vu, es que ya lo he hecho antes pero entendiendo menos al hacer los ejercicios de dos libros.
Crear el IP
- Tasks -> manage IP -> New IP Location
- Part: xc7z020clg400-1
- Target Language: Verilog
- Crear y seleccionar una carpeta, en esta aparecerá todo lo que cree Vivado
- Tools -> Create and Package New IP
- Create a new AXI4 peripheral
- Name: ip_md5
- Number of registers:7
- Interfaces: quizás quitar el "00"
- Next Step: Edit IP
- Copiar los archivos del proyecto original a ip_repo/ip_md5_1.0/hdl
- Agregarlos con Add Design Sources
- mejor NO copy sources into IP Directory
- en este momento
- ya se ha creado el C con los drivers de bajo nivel
- es buena idea hacer un commit
- Editar el ip de S_AXI, ip_md5_v1_0_S_AXI_inst
- Acá va la magia, ver luego
- Flow -> Run Synthesis
- Flow -> Package IP
- identification
- add category
- file groups
- merge changes from file groups wizard
- customization parameters
- merge changes from customization parameters wizard
- ports and interfaces
- hay que ver que esté lo que hayas puesto, en este caso status
- review and package
- re-package IP
- Otro buen momento para un commit
- close project
Crear el proyecto
- File -> project -> new
- location lo puse a la par que ip_repo
- varios next
- choose board -> pynq-z2
- varios next
- Settings
- Project Settings
- IP
- Repository -> ADD
- lo del paso Crear IP
- IP Integrator -> Create block design
- Add IP -> zynq
- run block automation
- re-customize IP ( doble click)
- ps-pl configuration
- general
- enable clock resets
- fclk_reset0_n
- Axi non secure enablement
- gp master axi interface
- m axi gp0 interface ON
- MIO Configuration
- I/O Peripherals
- UART 0 -> MIO 14::15
- clock configuration
- pl fabric clocks
- fclk_clk0 -> 100
- Add IP ->
- run connection automation
- si tenías ports
- make external
- agregar el xdc y ajustarlo
- validate design
- source ->design_1.bd -> create hdl wrapper
- source -> design_1.bd -> generate output products (paciencia)
- Program and debug
- generate bitstream (más paciencia)
- file
- export
- export hardware -> include bitstream
- file
- launch sdk
SDK
- comprobar en system.hdf que esté la IP y la uart
- comprobar que en wrapper platform esten los drivers
- file
- new
- application project
- empty application template
- comprobar bsp-> ps7_cortexa9_0-> include -> ip_md5.h
- el programa en C que quieras, otro día vemos más detalles.
- botón derecho sobre el proyecto -> run as -> launch on hardware (GDB)
- un segundo antes abriste la terminal:
- miniterm.py /dev/ttyUSB1 115200
- y para un programa muy sencillo:
printf("MD5 Brute Forcer SelfTest\r\n");
MD5_ACCELERATOR_Reg_SelfTest(
XPAR_MD5_ACCELERATOR_0_S_AXI_BASEADDR
);
- una salida muy sencilla:
Salida seft test |
Detalles
En el comienzo me equivoqué con el conteo de registros, pensé que eran 6, sin embargo fue intutitiva la corrección del hdl generado. Como por otros motivos tuve que arrancar de cero, al comparar la nueva generación con lo corregido comprobé que la corrección fué correcta.
Respecto a la paciencia en "Generate Output Products", nunca avisa que termina y arriba a la derecha el iconito de trabajando queda activo y dice "Synthesis out-of-date_". La manera de saber cuando ha terminado es mirando en la ventanita de Design Runs.
output products corriendo |
output products finalizado |
La magia
Primer nivel del wrapper
Si tu IP no usa puertos, no hay nada que tocar. En mi caso, para diagnosticar puse unos puertitos y se los conecté.
va en la interfaz:
output wire [5:0] status,
en la instanciación de S_AXI:
.status(status),
Segundo nivel del wrapper
Si tu IP no usa puertos, no hay nada que tocar en la interfaz, en este caso si, entonces:
output wire [5:0] status,
Luego van los registros de salida:
// Add extra user logic register here
wire [C_S_AXI_DATA_WIDTH-1:0] target_o;
wire [C_S_AXI_DATA_WIDTH-1:0] status_o;
// I/O Connections assignments
En donde se leen, hay que reemplzar los registros slaves por estos nuevos:
// Address decoding for reading registers
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
3'h0 : reg_data_out <= slv_reg0;
3'h1 : reg_data_out <= slv_reg1;
3'h2 : reg_data_out <= slv_reg2;
3'h3 : reg_data_out <= slv_reg3;
3'h4 : reg_data_out <= slv_reg4;
3'h5 : reg_data_out <= target_o;
3'h6 : reg_data_out <= status_o;
default : reg_data_out <= 0;
endcase
Y por último, la conexión de cada bit de status al registro de status y la instanciación de nuestro IP:
// Add user logic here
assign status = {status_o[0],status_o[1],
status_o[2],status_o[3],
status_o[4],status_o[5]};
driver driver (
.CLK(S_AXI_ACLK),
.CPU_RESETN(S_AXI_ARESETN),
.target_selected({slv_reg3,slv_reg2,slv_reg1,slv_reg0}),
.enable_switch(slv_reg4[0]),
.target(target_o),
.status_paused(status_o[0]),
.status_running(status_o[1]),
.status_warming(status_o[2]),
.status_found(status_o[3]),
.status_done(status_o[4]),
.enabled(status_o[5])
);
// User logic ends
Cuando metés la pata en el IP
La recomendación que he recibido y que sufrí no respetar, es si algo está mal, empezar otra vez de cero. Me parece que no hace falta tanto como de cero, estoy seguro que cuando incorporé los puertos de diagnóstico no lo hice, pero si tirar la sdk.
Edición del IP
- Tasks -> manage IP -> Open IP Location
- elegir el ip -> edit in IP Packager
- Corregir el HDL
- Acá va la magia, corregida
- Flow -> Run Synthesis
- Flow -> Package IP
- quizás File Groups
- review and package
- re-package IP
Editar el proyecto
- File -> project -> recent
- IP Integrator -> open block design
- aparece un mensaje diciendo que hay que hacer upgrade
- report ip status
- upgrade selected
- te ofrece generate output products (paciencia)
- Program and debug
- generate bitstream (más paciencia)
- [opcional] borrar el .sdk para evitar conflictos
- file
- export
- export hardware -> include bitstream
- file
- launch sdk
Respecto a borrar el sdk antes de reexportar, no te olvides de tener copia o todo versionado para recuperar lo que ya hayas hecho. Debido a que mi IP usa Xil_In y Xil_out, provistos por xgpio.h, cada vez tuve que restaurarlos, obtenidos originalmente de lo generador por uno de los labs.
Simulación
Agregué un test bench conectado al componente y a ese testbench lo puse como top. Si ejecutas la simulación con el wrapper como top, estás muerto, tendrías que generar los estímulos para AXI, olvidate...
Notas relacionadas por el lado de EAMTA 2021:
- 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