Archives mensuelles : mars 2022

sv2chisel, le convertisseur (System)Verilog vers Chisel

Le monde du FPGA (et de l’ASIC) regorge aujourd’hui de langages de description matériel. Au Verilog et VHDL s’ajoute maintenant tout un tas de langages comme Migen, Clash, BlueSpec, Amaranth, Chisel, SpinalHDL, Silice, … et j’en oublie plein. Tous ces langages permettent de générer du Verilog. Les possibilité de conversion de VHDL vers Verilog ne sont maintenant plus une utopie grâce aux évolutions de GHDL et de Yosys.

Bref, il existe désormais toujours une possibilité de convertir l’intégralité du projet en Verilog de manière à le simuler et synthétiser avec les outils conçus pour lui.

C’est quelque chose de très appréciable pour faire de la réutilisation de code. Il n’est plus nécessaire de re-concevoir un composant en VHDL tout ça parce que le contrôleur open source qui nous est nécessaire est codé en Verilog.

L’homogénéité de langage des sources d’un projet peut cependant être appréciable dans certain cas. Notamment quand le langage de description possède ses propres librairies de simulation comme c’est le cas en Chisel.

On peut certes instancier les «sous»-modules Verilog au moyen de BlackBox, mais ils ne seront pas simulable avec ChiselTest par exemple car treadle se cassera les dents dessus.

C’est là qu’intervient le nouveau projet nommé sv2chisel pour convertir du (system)Verilog en chisel.

Je vous propose ici de tester ensemble l’utilitaire dans un cas pratique. Je souhaite convertir le module Verilog fake_differential du projet d’exemple de l’ulx3s qui permet de générer un signal HDMI différentiel pour l’intégrer dans le projet HdmiCore écrit en Chisel. L’objectif étant de porter le projet HdmiCore sur la plate-forme ulx3s en restant dans du pure Chisel.

Installation de l’outil

Toutes les caractéristiques et limitations du convertisseur sont données sur le wiki. Pour l’installer nous allons cloner le projet github. Le projet n’en est pas à sa version 1.0, il est sans doute préférable de «travailler» sur le main du git plutôt que sur une release.

$ git clone https://github.com/ovh/sv2chisel.git
$ cd sv2chisel

Les étapes d’installations depuis les sources sont données dans le readme. Il faut publier localement sv2chisel ainsi que les «helpers» :

$ sbt publishLocal

Cette commande fonctionne pas chez moi, je pensais naïvement que c’était la même commande que celle consistant à lancer sbt puis taper «publishLocal» mais non 😉

Donc pour publier localement, on fera plutôt comme recommandé dans le readme :

$ sbt
sbt:sv2chisel> publishLocal
sbt:sv2chisel> helpers/publishLocal
sbt:sv2chisel> assembly

La commande «assembly» génère le fichier jar exécutable.

Le binaire de l’utilitaire est généré dans le répertoire utils/bin/ et se nomme tout simplement sv2chisel

$ ./sv2chisel -help
sv2chisel [Options] sv_files... or sv2chisel [Options] -c config_file

Commons Options:
    -l, --log-level <error|warn|struct|info|debug|trace>
                                     Logger verbosity level
    -L, --class-log-level CLASS_NAME:<error|warn|struct|info|debug|trace>
                                     Logger verbosity level within given CLASS_NAME (useful for transforms)
    -o, --emission-path PATH         Base emission path

Config File (prio over manually specified files):
    -c, --config-file FILE           Yaml Configuration File

Manual command-line configuration
    -i, --base-path PATH             Base path for files
    -n, --name NAME                  Project name
    -h, --help                       Show this message

Si l’on regarde dans le fichier on trouve un simple lien vers l’archive «jar» se trouvant dans le même répertoire:

$ ls 
sv2chisel  sv2chisel.jar

$ cat sv2chisel
#!/bin/bash

path=`dirname "$0"`
cmd="java -cp ${path}/sv2chisel.jar sv2chisel.Main ${@:1}"

Conversion

Pour convertir en Chisel, on peut simplement donner les noms des fichiers sources en arguments:

$ ./sv2chisel fake_differential.v
[log] ---- Processing project ----
[log] ############# Parsing fake_differential.v #############
[log] ######### Elapsed time for fake_differential.v #########
[log] # Lexing+Parsing Time : 335.206505 ms
[log] # Mapping to IR Time : 126.985877 ms
[log] ######### Executing 18 transforms #########
[log] ####### sv2chisel.transforms.CheckUseBeforeDecl #######
[log] # Elapsed time : 26.214516 ms
[log] ####### sv2chisel.transforms.CheckScopes #######
[log] # Elapsed time : 7.222317 ms
[log] ####### sv2chisel.transforms.CheckBlockingAssignments #######
[log] # Elapsed time : 1.448437 ms
[log] ####### sv2chisel.transforms.InferDefLogicClocks #######
[info] Registering a new clock clk_shift for module fake_differential (non blocking assignment) at fake_differential.v:3:0>>54:0
[warn] Unable to find module module ODDRX1F instanciated as ddr_p_instance in current module fake_differential for clock inference processing. at fake_differential.v:33:10>>41:11
[warn] Unable to find module module ODDRX1F instanciated as ddr_n_instance in current module fake_differential for clock inference processing. at fake_differential.v:42:10>>50:11
[log] # Elapsed time : 41.125895 ms
[log] ####### sv2chisel.transforms.PropagateClocks #######
[warn] Module ODDRX1F referenced by instance ddr_p_instance cannot be found in current design. Clock & Reset management might be inaccurate. at fake_differential.v:33:10>>41:11
[warn] Module ODDRX1F referenced by instance ddr_n_instance cannot be found in current design. Clock & Reset management might be inaccurate. at fake_differential.v:42:10>>50:11
[log] # Elapsed time : 1.878423 ms
[log] ####### sv2chisel.transforms.FlowReferences #######
[info] Declaring actual port directions for module fake_differential at fake_differential.v:5:2->8
[info] Running FlowReference Transform another time on module fake_differential at fake_differential.v:3:0>>54:0
[log] # Elapsed time : 28.311422 ms
[log] ####### sv2chisel.transforms.InferUInts #######
[info] Converting in_clock to UInt based on its usage in the module at fake_differential.v:7:9->11
[info] Converting tmds[_] to UInt based on its usage in the module at fake_differential.v:11:10->12
[log] # Elapsed time : 30.181078 ms
[log] ####### sv2chisel.transforms.InferParamTypes #######
[log] # Elapsed time : 5.803376 ms
[log] ####### sv2chisel.transforms.TypeReferences #######
[critical] Unsupported Type 'Bool' for subindex expression 'out_n[i]' at fake_differential.v:47:15->22
[log] # Elapsed time : 18.082934 ms
[log] ####### sv2chisel.transforms.LegalizeExpressions #######
[warn] Unknown remote type for port #2 (Q) of instance ddr_p_instance of module ODDRX1F: casting by reference by default at fake_differential.v:38:12->23
[critical] Unsupported Type 'Bool' for subindex expression 'out_n[i]' at fake_differential.v:47:15->22
[warn] Unknown remote type for port #2 (Q) of instance ddr_n_instance of module ODDRX1F: casting by reference by default at fake_differential.v:47:12->23
[log] # Elapsed time : 29.292823 ms
[log] ####### sv2chisel.transforms.FixFunctionImplicitReturns #######
[log] # Elapsed time : 1.314473 ms
[log] ####### sv2chisel.transforms.NameInstancePorts #######
[log] # Elapsed time : 2.628666 ms
[log] ####### sv2chisel.transforms.RemovePatterns #######
[log] # Elapsed time : 4.862502 ms
[log] ####### sv2chisel.transforms.RemoveConcats #######
[log] # Elapsed time : 3.143862 ms
[log] ####### sv2chisel.transforms.AddDontCare #######
[log] # Elapsed time : 1.28653 ms
[log] ####### sv2chisel.transforms.LegalizeParamDefaults #######
[warn] Cannot find module ODDRX1F in current project at fake_differential.v:33:10>>41:11
[warn] Cannot find module ODDRX1F in current project at fake_differential.v:42:10>>50:11
[log] # Elapsed time : 4.072062 ms
[log] ####### sv2chisel.transforms.FixReservedNames #######
[log] # Elapsed time : 4.126536 ms
[log] ####### sv2chisel.transforms.ToCamelCase #######
[log] # Elapsed time : 0.830815 ms
[log] # Total Elapsed time running transforms : 216.675871 ms
[log] ######### EMISSION #########
[log] ######### CHISELIZING fake_differential.v #########
[info] At fake_differential.v:11: Emitting unpacked for node tmds
[info] At fake_differential.v:18: Emitting unpacked for node R_tmds_p
[info] At fake_differential.v:18: Emitting unpacked for node R_tmds_n
[log] # Elapsed time : 21.267262 ms
[log] ######### EMITTING to /fake_differential.scala #########
Exception in thread "main" java.io.FileNotFoundException: /fake_differential.scala (Permission denied)
at java.base/java.io.FileOutputStream.open0(Native Method)
at java.base/java.io.FileOutputStream.open(FileOutputStream.java:291)
at java.base/java.io.FileOutputStream.(FileOutputStream.java:234)
at java.base/java.io.FileOutputStream.(FileOutputStream.java:123)
at java.base/java.io.FileWriter.(FileWriter.java:66)
at sv2chisel.Emitter$.$anonfun$emitChisel$9(Emitter.scala:174)
at sv2chisel.Utils$.time(Utils.scala:185)
at sv2chisel.Emitter$.$anonfun$emitChisel$1(Emitter.scala:163)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:286)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
at scala.collection.TraversableLike.map(TraversableLike.scala:286)
at scala.collection.TraversableLike.map$(TraversableLike.scala:279)
at scala.collection.AbstractTraversable.map(Traversable.scala:108)
at sv2chisel.Emitter$.emitChisel(Emitter.scala:134)
at sv2chisel.Driver$.emitChisel(Driver.scala:66)
at sv2chisel.Main$.$anonfun$new$10(Main.scala:159)
at scala.collection.immutable.List.foreach(List.scala:431)
at sv2chisel.Main$.delayedEndpoint$sv2chisel$Main$1(Main.scala:157)
at sv2chisel.Main$delayedInit$body.apply(Main.scala:55)
at scala.Function0.apply$mcV$sp(Function0.scala:39)
at scala.Function0.apply$mcV$sp$(Function0.scala:39)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
at scala.App.$anonfun$main$1$adapted(App.scala:80)
at scala.collection.immutable.List.foreach(List.scala:431)
at scala.App.main(App.scala:80)
at scala.App.main$(App.scala:78)
at sv2chisel.Main$.main(Main.scala:55)
at sv2chisel.Main.main(Main.scala)

Après de multiple messages plus ou moins critiques, la commande se termine sur une étonnante erreur java de fichier non trouvé. Visiblement il faut lui fournir le path complet en argument (sans doute un bug) :

 ./sv2chisel /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v 
[log]  ---- Processing project  ---- 
[log] ############# Parsing /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v #############
[log] ######### Elapsed time for /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v #########
[log] # Lexing+Parsing Time : 337.962186 ms
[log] # Mapping to IR Time  : 123.022396 ms
[log] ######### Executing 18 transforms #########
[log]    ####### sv2chisel.transforms.CheckUseBeforeDecl #######
[log]    # Elapsed time : 24.704003 ms
[log]    ####### sv2chisel.transforms.CheckScopes #######
[log]    # Elapsed time : 6.588446 ms
[log]    ####### sv2chisel.transforms.CheckBlockingAssignments #######
[log]    # Elapsed time : 1.838544 ms
[log]    ####### sv2chisel.transforms.InferDefLogicClocks #######
[info] Registering a new clock `clk_shift` for module fake_differential (non blocking assignment) at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:3:0>>54:0
[warn] Unable to find module module ODDRX1F instanciated as ddr_p_instance in current module fake_differential for clock inference processing. at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:33:10>>41:11
[warn] Unable to find module module ODDRX1F instanciated as ddr_n_instance in current module fake_differential for clock inference processing. at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:42:10>>50:11
[log]    # Elapsed time : 37.088031 ms
[log]    ####### sv2chisel.transforms.PropagateClocks #######
[warn] Module ODDRX1F referenced by instance ddr_p_instance cannot be found in current design. Clock & Reset management might be inaccurate. at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:33:10>>41:11
[warn] Module ODDRX1F referenced by instance ddr_n_instance cannot be found in current design. Clock & Reset management might be inaccurate. at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:42:10>>50:11
[log]    # Elapsed time : 1.73635 ms
[log]    ####### sv2chisel.transforms.FlowReferences #######
[info] Declaring actual port directions for module fake_differential at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:5:2->8
[info] Running FlowReference Transform another time on module fake_differential at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:3:0>>54:0
[log]    # Elapsed time : 25.221955 ms
[log]    ####### sv2chisel.transforms.InferUInts #######
[info] Converting in_clock to UInt based on its usage in the module at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:7:9->11
[info] Converting tmds[_] to UInt based on its usage in the module at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:11:10->12
[log]    # Elapsed time : 29.58874 ms
[log]    ####### sv2chisel.transforms.InferParamTypes #######
[log]    # Elapsed time : 5.646461 ms
[log]    ####### sv2chisel.transforms.TypeReferences #######
[critical] Unsupported Type 'Bool' for subindex expression 'out_n[i]' at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:47:15->22
[log]    # Elapsed time : 18.257447 ms
[log]    ####### sv2chisel.transforms.LegalizeExpressions #######
[warn] Unknown remote type for port #2 (Q) of instance ddr_p_instance of module ODDRX1F: casting by reference by default at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:38:12->23
[critical] Unsupported Type 'Bool' for subindex expression 'out_n[i]' at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:47:15->22
[warn] Unknown remote type for port #2 (Q) of instance ddr_n_instance of module ODDRX1F: casting by reference by default at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:47:12->23
[log]    # Elapsed time : 21.168114 ms
[log]    ####### sv2chisel.transforms.FixFunctionImplicitReturns #######
[log]    # Elapsed time : 0.631086 ms
[log]    ####### sv2chisel.transforms.NameInstancePorts #######
[log]    # Elapsed time : 1.467731 ms
[log]    ####### sv2chisel.transforms.RemovePatterns #######
[log]    # Elapsed time : 5.09245 ms
[log]    ####### sv2chisel.transforms.RemoveConcats #######
[log]    # Elapsed time : 2.749951 ms
[log]    ####### sv2chisel.transforms.AddDontCare #######
[log]    # Elapsed time : 1.251281 ms
[log]    ####### sv2chisel.transforms.LegalizeParamDefaults #######
[warn] Cannot find module ODDRX1F in current project at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:33:10>>41:11
[warn] Cannot find module ODDRX1F in current project at /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:42:10>>50:11
[log]    # Elapsed time : 3.092851 ms
[log]    ####### sv2chisel.transforms.FixReservedNames #######
[log]    # Elapsed time : 4.132691 ms
[log]    ####### sv2chisel.transforms.ToCamelCase #######
[log]    # Elapsed time : 0.890969 ms
[log] # Total Elapsed time running transforms : 195.82181 ms
[log] ######### EMISSION #########
[log] ######### CHISELIZING /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v #########
[info] At /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:11: Emitting unpacked for node tmds
[info] At /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:18: Emitting unpacked for node R_tmds_p
[info] At /opt/chiselmod/sv2chisel/utils/bin/fake_differential.v:18: Emitting unpacked for node R_tmds_n
[log] # Elapsed time : 25.374274 ms
[log] ######### EMITTING to //opt/chiselmod/sv2chisel/utils/bin/fake_differential.scala #########
[log] # Elapsed time : 17.429649 ms

Il y a sans doute beaucoup de chose a parametrer aux petits oignons pour bien utiliser l’outils, mais le résultat «en l’état» est déjà assez intéressant (commentaires FLF ajoutés):

package // FLF: à rajouter à la main ?
// FLF: on comprend pourquoi il voulait un path complet,
//      il le prend pour le nom du package
package .opt.chiselmod.sv2chisel.utils.bin

import chisel3._
// FLF: commentaires gardés, bien.
// DDR mode uses Lattice ECP5 vendor-specific module ODDRX1F

class fake_differential() extends Module { // used only in DDR mode
  // [1:0]:DDR [0]:SDR TMDS
  val in_clock = IO(Input(UInt(2.W)))
  val in_red = IO(Input(Bool()))
  val in_green = IO(Input(Bool()))
  val in_blue = IO(Input(Bool()))
  // [3]:clock [2]:red [1]:green [0]:blue 
  val out_p = IO(Output(Vec(4, Bool())))
  val out_n = IO(Output(Bool()))
// FLF: hmm, j'aurais pas traduit un tableau «wire» par une Mem() 
//      chisel, pas sûr que ça marche bien cette affaire.
  val tmds = Mem(4,UInt(2.W)) 
  tmds(3) := in_clock
  tmds(2) := in_red
  tmds(1) := in_green
  tmds(0) := in_blue

  // register stage to improve timing of the fake differential
  val R_tmds_p = Mem(4,Vec(2, Bool())) 
  val R_tmds_n = Mem(4,Vec(2, Bool())) 
  // genvar i;
  for(i <- 0 until 4){
    R_tmds_p(i) := tmds(i).asBools
    R_tmds_n(i) := ( ~tmds(i)).asBools
  }

  // output SDR/DDR to fake differential

  // FLF: les generate sont détecté et traduit également.
  // genvar i;
  for(i <- 0 until 4){
    // FLF: connexion des primitives sans broncher
    //      Il faudra tout de même inclure la définition
    //      de la blackbox à la main par la suite (import)
    val ddr_p_instance = Module(new ODDRX1F)
    ddr_p_instance.D0 := R_tmds_p(i)(0)
    ddr_p_instance.D1 := R_tmds_p(i)(1)
    out_p(i) := ddr_p_instance.Q.asTypeOf(out_p(i))
    ddr_p_instance.SCLK := clock
    ddr_p_instance.RST := 0.U
    val ddr_n_instance = Module(new ODDRX1F)
    ddr_n_instance.D0 := R_tmds_n(i)(0)
    ddr_n_instance.D1 := R_tmds_n(i)(1)
    out_n(i) := ddr_n_instance.Q.asTypeOf(out_n(i))
    ddr_n_instance.SCLK := clock
    ddr_n_instance.RST := 0.U
  }

}

Conclusion

Visiblement, le code généré doit être passé en revue par un ou une humaine histoire de corriger quelques imprécisions.

Mais cette relecture est facile, le code est très lisible et bien indenté. On retrouve les noms des signaux, variables, registres, modules Verilog. On est loin des bouillies de conversion où le code généré ressemble plus à un binaire compilé qu’à un code source «versionnable». Et cette saine relecture est de toute manière indispensable si l’on souhaite se reposer sur ce nouveau code dans la suite de son projet.

C’est un outil qui va vite devenir indispensable lorsque le besoin de convertion de code open-source se fera sentir. Et c’est une belle passerelle pour tous les habitués du Verilog qui souhaiteraient se lancer dans ce langage de haut niveau qu’est Chisel.

Des dire de l’équipe, l’outil a été testé avec succès sur le code du processeur RISC-V PicoRV32 développé par Claire Clifford (autrice de Yosys) que l’on retrouve un peu partout dans les projets open-source hardware.

C’est également une surprise de voir que ce projet est né au sein du laboratoire OVHCloud. Où l’on découvre que le fleurons du Claude français (cocorico) finance la recherche sur le matériel libre. Ceux qui ont besoin d’un article plus académique pour découvrir l’outil iront lire le papier de l’équipe ici.

ULX3S

Ho mais je me rend compte que je n’avais encore rien écrit sur la carte ULX3S commandée l’été dernier. Il faut dire que les délais d’approvisionnement étant ce qu’ils sont aujourd’hui la carte a tout de même mis presque six mois à arriver. J’ai donc eu tout le temps de passer à autre chose.

Donc oui, après m’être posé la question, j’ai opté pour l’ULX3S au détriment de l’orangecrab. La carte, conçue par le Hackerspace Radiona de Zagreb (croatie) arrive dans un petit carton muni de quelques accessoire «pmod» pour ajouter un second port HDMI, des USB et autres header he10.

L’ULX3S et ses adaptateurs «pmod»

La carte a tout ce qu’il faut pour faire une console de jeux 🙂 Mais pour le moment, on va surtout s’intéresser à la sortie HDMI, après avoir déballé la bête.

Mise en route

Un guide de mise en route est donné sur le github officiel. Pour démarrer la carte il suffit de brancher l’ordinateur sur l’usb de gauche.

Branchement de l’usb pour programmer la carte (src : quickstartguide)

Ce qui a pour effet d’allumer quelques leds de toutes les couleurs

\o/ plein de LEDs multicolors

et de monter un driver tty sur le pc host :

$ dmesg
[1956889.190788] usb 1-1.1.2: new full-speed USB device number 16 using xhci_hcd
[1956889.300502] usb 1-1.1.2: New USB device found, idVendor=0403, idProduct=6015, bcdDevice=10.00
[1956889.300504] usb 1-1.1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[1956889.300506] usb 1-1.1.2: Product: ULX3S FPGA 85K v3.0.8
[1956889.300507] usb 1-1.1.2: Manufacturer: FER-RADIONA-EMARD
[1956889.300508] usb 1-1.1.2: SerialNumber: E20000
[1956889.308375] ftdi_sio 1-1.1.2:1.0: FTDI USB Serial Device converter detected
[1956889.308401] usb 1-1.1.2: Detected FT-X
[1956889.308597] usb 1-1.1.2: FTDI USB Serial Device converter now attached to ttyUSB0

N’oublions pas que le FPGA est un ECP5, il y a donc tous les outils opensource disponibles pour développer avec. De plus, radiona fournie la toolchain précompilé pour la carte, il n’y a plus qu’à la télécharger et l’installer comme expliqué dans le manuel (424Mo pour un pc x64).

$ cd /opt/
$ mkdir ulx3s
$ cd ulx3s/
$ wget https://github.com/YosysHQ/oss-cad-suite-build/releases/download/2022-03-17/oss-cad-suite-linux-x64-20220317.tgz
$ tar xf oss-cad-suite-linux-x64-20220317.tgz

Si on veut faire clignoter vite vite vite, dans relancer de synthèse on peut tout simplement cloner le projet «blink» et télécharger le bitstream. À titre personnel je préfère utiliser openFPGALoader (avant même d’en tester un autre ;).

$ cd /opt/ulx3s
$ git clone https://github.com/ulx3s/blink.git
$ cd blink/
$ tree
.
├── blink_12f.bit
├── blink_45f.bit
├── blink_85f.bit
├── blinky.v
├── blinky.ys
├── LICENSE
├── Makefile
├── README.md
└── ulx3s_v20.lpf

0 directories, 9 files
$ openFPGALoader -bulx3s  blink_85f.bit
Jtag probe limited to 3MHz
Jtag frequency : requested 6000000Hz -> real 3000000Hz
ret 0
Open file: DONE
Parse file: DONE
Enable configuration: DONE
SRAM erase: DONE
Loading: [==================================================] 100.00%
Done
Disable configuration: DONE

Le résultat n’est pas une LED qui clignote, mais 6 LEDs multicolors qui clignotent (qui compte en binaire).

Le projet blink fourni un makefile pour reconstruire le bitstream si l’on veut tester la toolchain :

$ export PATH=/opt/ulx3s/oss-cad-suite/:$PATH
$ make ulx3s.bit
$ openFPGALoader -bulx3s ulx3s.bit

Et voila \o/, c’est tout pour la prise en main !

La suite

La suite va consister à adapter le projet HdmiCore pour la sortie HDMI de la carte.

Ressources

Déballage de la TangNano9k

La boite de la Tang Nano 9K

Ça y est, le colis contenant la carte de développement Tang Nano 9k est arrivé. Contrairement à la TangNano4k je ne l’ai pas reçue rapidement, il a fallu attendre environ deux mois. Mais elle est bien là maintenant.

La TangNano9k sortie de sa boite

La petite carte, muni d’un littlebee GW1NR-LV9 est tout de même plus grande que les petites sœur. Cette carte est plus «grande» que la 4k mais elle possède autant de PSRAM (64Mbits) et ne possède pas de cœur ARM. La carte possède cependant plus de LUT.

Tang Nano 9K, Tang Nano 4k et Tang Nano

La fiche descriptive d’aliexpress propose un tableau comparatif des trois cartes disponible pour environ $15.

Table de comparaison des différentes TangNano proposé sur aliexpress

Au branchement, les deux UART du BL702 apparaissent :

[1874406.879770] usb 1-1.1.3: new full-speed USB device number 96 using xhci_hcd
[1874406.980305] usb 1-1.1.3: not running at top speed; connect to a high speed hub
[1874406.981788] usb 1-1.1.3: New USB device found, idVendor=0403, idProduct=6010, bcdDevice= 5.00
[1874406.981794] usb 1-1.1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[1874406.981797] usb 1-1.1.3: Product: JTAG Debugger
[1874406.981800] usb 1-1.1.3: Manufacturer: SIPEED
[1874406.981803] usb 1-1.1.3: SerialNumber: FactoryAIOT Pro
[1874406.991536] ftdi_sio 1-1.1.3:1.0: FTDI USB Serial Device converter detected
[1874406.991586] usb 1-1.1.3: Detected FT2232C
[1874406.992995] usb 1-1.1.3: FTDI USB Serial Device converter now attached to ttyUSB0
[1874406.993170] ftdi_sio 1-1.1.3:1.1: FTDI USB Serial Device converter detected
[1874406.993213] usb 1-1.1.3: Detected FT2232C
[1874406.993538] usb 1-1.1.3: FTDI USB Serial Device converter now attached to ttyUSB1

Et les 6 LED rouges clignotent en même temps.

Pinout de la TangNano9k trouvé sur la fiche aliexpress

Le part number du FPGA est GW1NR-LV9QN88PC6/I5 et peut être sélectionné pour la synthèse et le placement-routage avec le logiciel de gowin version 1.9.8.03.

[Article à éditer]

Ressources: