2019/12/29

Para estudiar The Zynq Book


Es un libro muy atado al producto... claro, se llama The Zynq Book, alguien en los comentarios de algún sitio que reclama por ello, pero ¿qué esperabas? Dice "con la colaboración de Xilinx" en la tapa.

Se puede obtener gratis, probablemente en http://www.zynqbook.com/download-book.php.



Tiene el problema de un fuerte sabor a marketing, muchas veces dice lo flexible, óptimo y adaptable que es Zynq. Luego hay un montón de información que es de algún modo genérica. Si tuviera la mitad de lo genérico y el cuádruple de lo de Zynq como para mantener la cantidad de páginas, hubiese sido excelente. La realidad es que a mi no me quedaron claras cosas como si el componente ethernet se puede acceder directamente desde la PL.

Lo bueno es que no explica nada de VHDL/Verilog/C/Assembly, supone que ya sabés.

Lo malo es que hay varios lugares donde se dan explicaciones de conceptos donde hubiese estado bueno un ejemplito en VHDL/Verilog.

Intel tiene algo parecido, con nombres como Arria, Stratix y Cyclone.

En apariencia, este tipo de SoC facilita esta evolución: de programar una CPU y diseñar hardware por separado a diseñar un sistema y con la ayuda de la herramienta implementar algunas partes en hardware y otras en software.

La idea es que lo simple y paralelizable va al hardware, lo complicado se queda en la CPU.


La verdad es que sea usando este tipo de SoC o los componentes separados no hace diferencia desde el punto de vista de la programación, incluso estoy seguro que el libro dice que lo que hagas en C/C++/SystemC sólo se va a ejecutar en un softcore, no es que generás código y la herramienta elige si ponerlo en los cores ARM. O al menos así era en 2014, tengo el "libro siguiente", motivo por el cual leí este pese a la mala crítica, quizás haya cambiado.

Me quedo con la idea de que el objetivo es hacer aceleradores para ser utilizados desde las CPU ARM, pero simplificando el diseño en la PL.


Zynq te permite desarrollar cosas que yo al menos no podría pues no tengo el conocimiento para interconectar una fpga con una cpu. Algo parecido a pasar de un micro + memoria(ram/rom) + uart a un microcontrolador que ya tiene todo adentro y sólo hay que configurar o ni eso.

De todos modos yo no puedo hacer nada con un zynq, necesito una Parallella, PYNQ o equivalente donde todo el hardware ya esté resuelto.

Los "ok" son relativos, para alguien que tiene experiencia de cada tema quizás estén de sobra, pero para mi siempre es un buen repaso.

  • 1 Intro ok
  • 2 Detalles hardware ok
  • 3 Detalles software, aplica a cualquier otro FPGA, ok
  • 4 Criterios de elección, ok
  • 5 Humo, completamente en vano
  • 6 Zedboard, ok para quien la tiene
  • 7 En vano
  • 8 Ejercicio
  • 9 Arquitectura de harware, modo superficial y adaptados a la arquitectura, ok
  • 10 Más detalles hardware, lo anterior aplicado a zynq, ok
  • 11 Más detalles software, aplica a cualquier otro FPGA, ok
  • 12 Ejercicio
  • 13 - 15 HLS, aplicable a cualquier FPGA, ok
  • 16 Ejercicio
  • 17 Ejercicio
  • 18 IP ok
  • 19 AXI ok
  • 20 Ejercicio
  • 21 Sistemas operativos ok
  • 22 - 24 Linux ok


Se complementa con unos tutoriales que están en http://www.zynqbook.com/download-tuts.html

Lo que me he propuesto es adaptar a mis placas PYNQ-Z2 ahora y algún día Parallella la experiencia desarrollada en los ejemplos prácticos.

Ejercicios

 

Te recomiendo que saltées esta parte y vayas directo a las conclusiones, a menos que estés siguiendo los tutoriales y te trabes, quizás algo te ayude.

Tambien si tenés una Zed o Zybo. En caso de otras placas, quizás quizás te sirva mirar por arriba lo que hice.


Estos son los pasos tomados de The_Zynq_Book_Tutorials_Aug_15.pdf, utilizando primero Vivado 2015.4, luego pasé a 2018.2 debido a que no vé la placa PYNQ.

Los dos primeros ejercicios consisten en pegarle unos IPs al Zynq y ejecutar un programa baremetal para prender los leds, luego leer los push buttons generando interrupciones y finalmente incorporar un timer, todo esto con AXI.

El tercero es de optimización, es un tanto avanzado para los básicos como yo, lo entiendo pero me dificultaría aplicarlo, pese a haber transitado el uso de PIPELINE en Forzando Brutalmente MD5.

El cuarto es crear tus propios IP, para usarlos en el quinto.


Todo versionado en github pero mal versionado pues está sin el .gitingore y además moví los ejercicios uno a tres así que no deben andar ni a palos, es más por backup que por proceso de desarrollo.



Exercise 1, First Designs on Zynq


Exercise 1A Creating a First IP Integrator Design


Registro los pasos tipo machete para futura referencia, te conviene seguir el tutorial, va todo igual salvo que hay que elegir la placa PYNQ.



Agregar la PYNQ a Vivado, con ayuda de https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/board_settings.html

dice que

<Xilinx installation directory>\Vivado\<version>\data\boards

y ahi hay dos carpetas, va en boards_files

Acá está la descripción para Vivado y acá el XDC


  • Create New Project
  • Elegir el board

Exercise 1B Creating a Zynq System in Vivado (2018.2)


  • Create Block Design (IP INTEGRATOR -> ...)
  • Add IP -> ZYNQ7 Processing System (Diagram -> ...)
  • Run Block Automation -> Apply Board Preset
  • Add IP -> GPIO (Diagram -> Add IP -> AXI GPIO)
  • Run Connection Automation -> S_AXI
  • Run Connection Automation - leds_4bits
  • File -> Save Block Design
  • Toos -> Validate Design
  • Windows -> sources
  • botón derecho -> Create HDL Wrapper
  • Generate Bitstream
  • Open Implemented Design
  • File -> Export -> Export Hardware -> include bitstream
  • File -> Launch SDK

Exercise 1C Creating a Software Application in the SDK

en particular en Import se usa lo de

The_Zynq_Book_Tutorial_Sources_Aug_15.zip,

la diferencia entre zybo y zed es el ancho de los leds, como PYNQ es 4 igual que Zybo, usé Zybo


kdiff3  zybo/first_zynq_design/LED_test_tut_1C.c zedboard/first_zynq_design/LED_test_tut_1C.c siempre ayuda para estos casos.

  • File -> New -> Application Project
  • Next -> Empty Application
  • Project Explorer -> el proyecto -> src -> Import -> ....
  • Xilinx Tools -> Program FPGA
  • Project Explorer -> el proyecto -> Run As -> Launch on Hardware

¡Anda!, ¡¡¡no lo puedo creer!!!




Exercise 2, Next Steps in Zynq SoC Design

2A-C Expanding the Basic IP Integrator Design

Podría continuar sobre el ejercicio 1 o empezar de cero, mejor para fijar los conocimientos. Las instrucciones ya están adaptadas a Vivado 2018.2


Es todo igual pero hay que agregar un AXI-GPIO extra y conectarle los botones.

Luego

  • Doble click axi_gpio_0 -> IP Configuration -> enable interrupt
  • Doble click processing_system_7 -> Page Navigator -> Interrupts -> 
    • Check Fabric Interrupts
    • Check Pl-PS Interrupt Ports -> IRQ_F2P[15:0]
  • Block Design -> Diagram -> connect
    • axi_gpio_0/ip2intc_irpt
    • processing_system_7/IRQ_F2P[0:0]
  • File -> Save Block Design
  • Tools -> Validate Block Design
y volvemos al caminito normal

  • Project Manager -> Sources -> right click on design -> Create HDL wrapper
  • Generate bitstream
  • (paciencia)
  • Open Implemented Design
  • File -> Export Hardware -> include bitstream
  • File -> Launch SDK
  • File -> New -> Application Project -> empty application
  • import...
  • Program FPGA
  • Y vuelve a andar, increible


Exercise2D Adding a Further Interrupt Source


Nada nuevo, sólo agregar un axi timer con la novedad de que hay que conectarlo a mano usando el IP concat, al pasar al SDK eliminar el proyecto e importar lo nuevo, interrupt_counter_tut_2D.c. Como me olvidé de versionar y taggear hasta el paso anterior, en mi código quedó con esta última versión.


Exercise 3 Designing With Vivado HLS


Exercise 3A Creating Projects in Vivado HLS

Van los pasos macheteados

  • Copiar sources/hls a tu workspace
  • Create New Project, con Project Location -> lo anterior
  • Add Files (Design Files) -> matrix_mult.cpp, matrix_mult.h
    • Top Function -> matrix_mult
  • Add Files (Testbench Files) -> matrix_mult_test.cpp
  • Solution Configuration
    • Clock Period -> 5
    • Boards -> elegí board
  • Close HLS
  • Open HLS Command Prompt
  • cd hasta tut3A
  • Otra vez kdiff3 al rescate, pues dice que ejecutes run_hls_zed.tcl o run_hls_zybo.tcl. La diferencia es part. De algún modo te enteras que es xc7z020clg400-1, con lo cual creás un run_hls_pynq.tcl 
  • vivado_hls -f run_hls_pynq.tcl
  • vivado_hls -p matrix_multlplier

Exercise 3B Design Optimisation in Vivado HLS

Lo que se hace es probar distintas soluciones de optimización hasta que alguna sea factible por timing.

  • Run C Simulation
  • C Synthesis
  • C/RTL Co-simulation -> VHDL
  • Project -> New Solution
    • Acá hay un problema con Part, no ve los boards, tuve que ponerle vía Part el correcto, xc7z020clg400-1
  • Select matrix_mult.cpp
  • Directives -> punto de inserción -> Insert Directive -> PIPELINE / ARRAY RESHAPE
  • C Synthesis 
    • Va a ir fallando según "punto de inserción" y la directiva que se use
  • Project -> Compare Reports -> Seleccionar los últimos y comparar...

Exercise 3C Interface Synthesis

  • cd tut3C
  • copiar run_hls_pynq.tcl de tut3A
  • vivado_hls -f run_hls_pynq.tcl
  • vivado_hls -p matrix_mult_prj
  • mirar el summary de la interface

Exercise 4 IP Creation

Exercise 4A Creating IP in HDL

  • Create New Project
    • no olvides poner VHDL como lenguaje que yo siempre me olvidé, esta vez sí hace diferencia
  • Tools -> Create and Package New IP
    • Create a new AXI4 peripheral 
    • Create Peripheral -> Edit IP
    •  se abrirá otra instancia
  •  Open led_controller_v1_0_S00_AXI.vhd
    • Agregar los ports de Zybo por el ancho de 4 bits
    • File -> Save
  • Open led_controller_v1_0.vhd
    • algo parecido

  • Package IP - led_controller
    • Customization Parameters
      • Merge changes from Customization Parameters Wizard
    • Ports and Interfaces -> check está ok
    • Review and Package -> edit packaging settings
    • Automatic behaviour, enable all (but Include source project archive in 2018.2)
    • Re-Package IP

  • Volver al proyecto original 
  • IP Integrator -> Create Block Design
    • Diagram -> Add IP -> led_controller
    • LEDs_out -> Right click -> Make external (ahi pone out_0)

Tip salvador para 2018.2, le pone al pin el nombre LEDs_out_0, hay que cambiarlo por LEDs_out
    • Add IP -> zynq7 processing system
    • Run Block Automation
    • Run Connection Automation
    • Tools -> Validate
  • Project Manager -> Sources -> Design Sources -> led_test_system -> Create HLD Wrapper 


  • Add Sources -> Constraints -> Create -> XDC -> pynq-z2_v1.0.xdc
  • Y acá hay que buscar en el XDC que bajamos en algún momento los nombres de los pines correspondientes a los leds:


set_property PACKAGE_PIN R14   [get_ports { LEDs_out[0] }]
set_property IOSTANDARD LVCMOS33  [get_ports { LEDs_out[0] }]

set_property PACKAGE_PIN P14   [get_ports { LEDs_out[1] }]
set_property IOSTANDARD LVCMOS33 [get_ports { LEDs_out[1] }]

set_property PACKAGE_PIN N16   [get_ports { LEDs_out[2] }]
set_property IOSTANDARD LVCMOS33 [get_ports { LEDs_out[2] }]

set_property PACKAGE_PIN M14   [get_ports { LEDs_out[3] }]
set_property IOSTANDARD LVCMOS33 [get_ports { LEDs_out[3] }]


  • Generate Bitstream
  • Open Implemented Design
  • File -> Export -> Export Hardware -> Include Bitstream
  • File -> Launch SDK

  • Luego en el SDK
  • File -> New -> Application Project
  • Empty Application
  • Xilinx Tool -> Repositories -> New
  • ip_repo -> led_controller (lo creado antes)
  • system.mss -> modify this BSP's Settings -> drivers -> led_controller
  • Project Explorer -> src -> import -> file system -> zybo -> led_controller
Aqui falla por undefined referencie to Xil_Out32, se corrige agregando a led_controller_test_tut_4A.c

#include "xil_io.h"

Sigamos
  • Xilinx -> Program FPGA
  • SDK Teminal -> Connect 
    • /dev/ttyUSB1 (o lo que haya)
  • Project Explorer -> Right Click -> Rus As -> Launch on Hardware(GDB)

Listo...

Exercise 4B Creating IP in MathWorks HDL Coder

Este implica usar MatLab, todo bien pero me aleja demasiado de mis propósitos, quizás algún día si me sobra tiempo lo haga. O eso es lo que había pensado hasta que ví que en la última parte hace falta lo generado por esta, así que a bajar el Matlab DEMO por 30 días.



  • Copiá la carpeta hdl_coder_lms a donde te guste
  • Dice que configures HDL Toolpath, no sé por qué con ISE, le puse directo Vivado:


hdlsetuptoolpath('ToolName', 'Xilinx Vivado', 'ToolPath', '/Xilinx/Vivado/2018.2/bin/vivado')

No dijo que estuviera mal, pero tampoco todo lo que el tutorial

  • Cambía al directorio de trabajo donde copiaste hdl_coder_lms
  • abrí lms.slx 
  • El mirar adentro es opcional
  • No pude hallar "HDL Code -> HDL workflow Advisor", pero si que yendo a Get Add-ons, buscar "hdl code", get trial  y un sales representative te contactará. 
Nuevamente se abre un nuevo mundo enorme y muy interesante de exploración que me alejan de mi propósito que es lograr un cierto dominio sobre Zynq y Vivado, lo siento Matlab, hasta aquí llegué.




Exercise 4C Creating IP in Vivado HLS

 

Este ejercicio al igual que el 3 me queda un poco grande
  • Abrir Vivado HLS
  • Create New Project
    • Add Files -> nco.cpp
    • Top Function ->nco
    • Add Test Files -> nco_tb.cpp
    • Part Selection -> usar part ya que no hay board
  • Ver *.cpp
  • Cambiar outfile a algo que te sirva
  • Run simulation
    • mirá el output
  • Seleccioná nco.cpp
  • Directive
    • Insertar todas las mencionadas
  • Run C Synthesis
  • Export RTL
Y en teoría esto sirve para el próximo

Exercise 5 Adventures with IP Integrator

Estos ejercicios integran lo anterior y dependen de generar un IP con Matlab que tal como relato arriba no pude lograr por motivos no técnicos.

Conclusiones


Pese a el problemita con Matlab, los ejercicios salvan al libro, si no sabés nada, tendrías que leer el libro, si sabés algo salteando los capítulos no ok y si sabés bastante quizás los ejercicios no te alcancen.

Los ejercicios en realidad son guías, si usas las versiones correctas y las placas consideradas sólo practicás recetas, quizás te cierre algún aprendizaje de la lectura del libro.



2019/12/22

VGA Rendering de simulación FPGA

Mientras estudiaba "Designing Video Game Hardware in Verilog" me hallé con que tenía que diagnosticar por que no funcionaban bien mis adaptaciones del código provisto a la Nexys 4 DDR que tengo con los ejemplos correspondientes a VGA (o mi doble adaptación a VGA por ser CRT).

Para no tener que pasar por todo el prolongado ciclo de modificar, sintetizar, implementar, generar el bitstream, burn it y tener que sacar el trasero de la silla para decirle al monitor que tome la entrada VGA en lugar del HDMI me hice un programita en TCL/TK que toma la salida de la simulación y me hace el render de las señales.

La verdad es que por lo valioso en términos educativos de este proyecto ni me molesté en ver si alguien ya lo había hecho, quizás por fin haya logrado aportar algo realmente útil. Mientras escribo esto veo que Xilinx tiene un repo de scripts para Vivado pero no llego a ver rápido si hay manera de ganarse una ventana dentro de la IDE, así que quedará para la Caja del Futuro.


En términos más formales:

El objetivo es hacer el render de una señal VGA generada probablemente por una simulación de un diseño Verilog o VHDL.

Los historias de usuario vienen a ser, "como usuario quiero que..."
  • Haga render de un frame
  • Haga render de varios frames consecutivos
  • Haga render de un frame  en "tiempo real", o sea, a medida que el simulador emita los datos
  • Haga render de varios frames consecutivos en "tiempo real"
  • Ajuste automático de resolución (640 x 480 la actual) 
  • Que entienda archivos standard tipo VCD
  • Que se pueda avanzar y retroceder
  • Que se pueda avanzar y retroceder usando el dispositivo ShuttleProV2


En verde lo que hice, no creo que avance con el resto pues esto es sólo un medio para lo que realmente quiero y no quiero que me distraiga.


Dado que hace muchos años trabajé con TCL/TK y me gustó y además Vivado usa TCL, más vale que empiece a recuperarlo, decidí usarlo para esta actividad.


En la carpeta "evolucion" dejé registrada la... evolución de mi acercamiento al problema, desde generar un patrón programáticamente en TCL/TK, pasando por mostrar las hsyncs y vsyncs, leer de un archivo, de STDIN y que finalmente funcione.

Los ejemplos 01_* a 04_* son los de "calibración", los restantes ya toman la salida de la simulación.





Entre las versiones 05_patternFromFile.tcl y 06_single_frame.tcl las diferencias significativas son:



  • Abstracción: en lugar de string index por todos lados, procs.
  • Lectura por STDIN
  • update para ver el rendering en tiempo real
  • y está bien alineado

La diferencia con la versión final, render.tcl es el multiframe


Con respecto a la salida de la simulación, primero investigué y no hay manera sencilla de acceder a lo generado pues está en una base de datos de formato desconocido para mi, así que opté por usar $strobe en el testbench con algo parecido a esto:



always @(negedge clock)
   $strobe("%b %b %b #%h%h%h", clock, hsync, sync, R, G, B);


Hay que generar el color tal que lo entienda TK o hacer una función adaptadora, opté por lo primero, mirá el código.


Podría quitar el clock ya que siempre es cero.

La simulación debe correr durante unos 8 ms para tener un frame completo entre vsyncs.




Me gustaría agregar colores distintos para las zonas no visibles que ahora está en negro y se confunde con la barra negra de la derecha, pero por ahora esto me sirve.


Es bastante lento, no me puse a optimizar, ni sé si se puede, de mis motivos originales sólo cumplo con no levantarme de la silla para cambiar la entrada del monitor.

Hay otra ventaja, la posibilidad de ver un sólo frame de una secuencia, que dependiendo del circuito real quizás no se pueda en la FPGA sin agregar lógica.




El video está fuertemente editado para que sólo se vea lo esencial de la interacción y el primer frame que no se muestra por no tener VSync está omitido, luego es tiempo real en una AMD A10-7700K Radeon R7.

Tambien corresponde a la versión de un solo frame, sin la simpática rayita blanca que muestra donde está dibujando, indispensable para multi frame.

El código en github

Esta es la captura de la última versión, con la simpática rayita y los límites de lo visible enmarcados en verde: