{"id":559,"date":"2017-04-05T13:43:54","date_gmt":"2017-04-05T12:43:54","guid":{"rendered":"http:\/\/www.fabienm.eu\/flf\/?p=559"},"modified":"2017-04-05T13:43:54","modified_gmt":"2017-04-05T12:43:54","slug":"les-blackbox-et-rawmodule-de-chisel3","status":"publish","type":"post","link":"http:\/\/www.fabienm.eu\/flf\/les-blackbox-et-rawmodule-de-chisel3\/","title":{"rendered":"Les BlackBox et RawModule de Chisel3"},"content":{"rendered":"<p>Quelque soit le langage HDL utilis\u00e9 il est tr\u00e8s important de se garder la possibilit\u00e9 d&rsquo;int\u00e9grer des modules provenant d&rsquo;autre langages et\/ou n&rsquo;ayant pas de descriptions HDL.<\/p>\n<p>C&rsquo;est par exemple le cas des primitives mat\u00e9riel permettant d&rsquo;instancier des modules int\u00e9gr\u00e9s au FPGA du constructeur au moyen de \u00abtemplate\u00bb Verilog : s\u00e9rialiseur\/d\u00e9s\u00e9rialiseur, PLL, entr\u00e9es\/sorties sp\u00e9cifiques, &#8230;<\/p>\n<p><strong>BlackBox<\/strong><\/p>\n<p>Pour int\u00e9grer ce genre de module dans son projet Chisel3 on utilise des \u00ab<a href=\"https:\/\/github.com\/ucb-bar\/chisel3\/wiki\/BlackBoxes\">BlackBox<\/a>\u00bb.\u00a0 L&rsquo;id\u00e9e est de d\u00e9crire les entr\u00e9es\/sorties du module ainsi que ses param\u00e8tres, et Chisel se chargera de convertir \u00e7a en une d\u00e9claration Verilog.<\/p>\n<p>Le probl\u00e8me est assez classique sur les kits de d\u00e9veloppement de Xilinx qui sont cadenc\u00e9 par une horloge diff\u00e9rentielle : Oblig\u00e9 d&rsquo;instancier un buffer diff\u00e9rentiel pour pouvoir r\u00e9cup\u00e9rer l&rsquo;horloge. Ce qui n&rsquo;est pas pr\u00e9vu dans la classe <a href=\"https:\/\/github.com\/ucb-bar\/chisel3\/wiki\/Modules\">Module<\/a> de base de Chisel3 puisque l&rsquo;horloge \u2212 tout comme le reset \u2212 est implicite.<\/p>\n<p>D&rsquo;apr\u00e8s la <a href=\"http:\/\/www.xilinx.com\/support\/documentation\/user_guides\/ug471_7Series_SelectIO.pdf\">documentation Xilinx<\/a>, le buffer diff\u00e9rentiel IBUFDS doit \u00eatre instanci\u00e9 de la mani\u00e8re suivante en Verilog pour que le logiciel de synth\u00e8se le rep\u00e8re et l&rsquo;instancie correctement:<\/p>\n<pre>IBUFDS #(\r\n    .DIFF_TERM(\"TRUE\"),\r\n    .IOSTANDARD(\"DEFAULT\")\r\n) ibufds (\r\n    .IB(ibufds_IB),\r\n    .I(ibufds_I),\r\n    .O(ibufds_O));\r\n<\/pre>\n<p>Cette instanciation est compos\u00e9e de deux param\u00e8tres \u00abgeneric\u00bb et de trois entr\u00e9es sorties.<\/p>\n<p>Une BlackBox() se comporte comme un Module() sans les horloges et reset implicites. De plus le nom des IO est recopi\u00e9 tel quel par Chisel, il n&rsquo;ajoute pas le pr\u00e9fixe \u00abio_\u00bb comme pour un module normale.<\/p>\n<p>Pour d\u00e9clarer ce buffer diff\u00e9rentiel en Chisel il suffira donc d&rsquo;\u00e9crire le code suivant:<\/p>\n<pre>import chisel3._\r\nimport chisel3.util._\r\nimport chisel3.experimental._\r\n\r\nclass IBUFDS extends BlackBox(\r\n    Map(\"DIFF_TERM\" -&gt; \"TRUE\",\r\n        \"IOSTANDARD\" -&gt; \"DEFAULT\")) {\r\n    val io = IO(new Bundle {\r\n        val O = Output(Clock())\r\n        val I = Input(Clock())\r\n        val IB = Input(Clock())})\r\n}<\/pre>\n<p>Le Map en param\u00e8tre de la class BlackBox() permet d&rsquo;ajouter les param\u00e8tres \u00abgeneric\u00bb et les entr\u00e9es sortie sont d\u00e9clar\u00e9s par la variable io.<\/p>\n<p>Il suffira alors de l&rsquo;instancier dans notre module top :<\/p>\n<pre>val ibufds = Module(new IBUFDS)\r\nibufds.io.I := clock_p\r\nibufds.io.IB:= clock_n\r\n<\/pre>\n<p>Pour que le code Verilog soit correctement \u00e9crit dans le fichier final.<\/p>\n<p><strong>Top RawModule<\/strong><\/p>\n<p>Maintenant que nous avons notre entr\u00e9e d&rsquo;horloge, notre but est d&rsquo;aller faire clignoter une led (quelle originalit\u00e9 !) en utilisant un compteur. Avec le module suivant:<\/p>\n<pre>class Blink extends Module {\r\n    val io = IO(new Bundle {\r\n        val led = Output(Bool())\r\n        })\r\n\r\n    val MAX_COUNT = 100000000\r\n\r\n    val count = Counter(MAX_COUNT)\r\n\r\n    count.inc()\r\n\r\n    io.led := 0.U\r\n    when(count.value &lt;= UInt(MAX_COUNT)\/2.U){\r\n    io.led := 1.U\r\n    }\r\n}<\/pre>\n<p>Ce module \u00e9tant un module \u00abnormal\u00bb l&rsquo;horloge et le reset sont implicite, alors comment allons nous faire pour qu&rsquo;il soit cadenc\u00e9 par la sortie du buffer IBUFDS ?<\/p>\n<p>On peut simplement les int\u00e9grer dans un Module() classique que l&rsquo;on appellera Top :<\/p>\n<pre>class Top extends Module {\r\n  val io = IO(new Bundle {\r\n    val clock_p = Input(Clock())\r\n    val clock_n = Input(Clock())\r\n    val led     = Output(Bool())\r\n  })\r\n\r\n  val ibufds = Module(new IBUFDS)\r\n  ibufds.io.I := io.clock_p\r\n  ibufds.io.IB:= io.clock_n\r\n\r\n  val blink = Module(new Blink)\r\n  blink.clock := ibufds.io.O\r\n  blink.reset := 1'0\r\n  io.led := blink.io.led }<\/pre>\n<p>Notez que pour connecter explicitement l&rsquo;horloge, la technique est en phase de d\u00e9veloppement mais il faut d\u00e9sormais utiliser la classe withClockAndReset()\u00a0 pour faire les choses proprement . Plut\u00f4t que :<\/p>\n<pre>  val blink = Module(new Blink)\r\n  blink.clock := ibufds.io.O\r\n  blink.reset := false.B\r\n  io.led := blink.io.led\r\n<\/pre>\n<p>Faire :<\/p>\n<pre>withClockAndReset(ibufds.io.O, false.B) {\r\n    val blink = Module(new Blink)\r\n    io.led := blink.io.led\r\n  }\r\n<\/pre>\n<p>Cette m\u00e9thode va fonctionner mais elle va nous ajouter les signaux clock et reset implicites. Signaux qui ne serviront pas \u00e0 grand chose dans notre cas et g\u00e9n\u00e9reront des warning p\u00e9nible dans le logiciel de synth\u00e8se:<\/p>\n<pre>module Top(\r\n<strong>  input   clock,<\/strong>\r\n<strong>  input   reset,<\/strong>\r\n  input   io_clock_p,\r\n  input   io_clock_n,\r\n  output  io_led\r\n);\r\n  wire  ibufds_IB;\r\n  wire  ibufds_I;\r\n  wire  ibufds_O;\r\n  wire  blink_clock;\r\n  wire  blink_reset;\r\n  wire  blink_io_led;\r\n  IBUFDS #(.DIFF_TERM(\"TRUE\"), .IOSTANDARD(\"DEFAULT\")) ibufds (\r\n    .IB(ibufds_IB),\r\n    .I(ibufds_I),\r\n    .O(ibufds_O)\r\n  );\r\n  Blink blink (\r\n    .clock(blink_clock),\r\n    .reset(blink_reset),\r\n    .io_led(blink_io_led)\r\n  );\r\n  assign io_led = blink_io_led;\r\n  assign ibufds_IB = io_clock_n;\r\n  assign ibufds_I = io_clock_p;\r\n  assign blink_clock = ibufds_O;\r\n  assign blink_reset = 1'h0;\r\nendmodule<\/pre>\n<p>C&rsquo;est pour cela qu&rsquo;une nouvelle hi\u00e9rarchie de classe est en d\u00e9veloppement pour les <a href=\"https:\/\/github.com\/ucb-bar\/chisel3\/pull\/469\">Module()<\/a>.<\/p>\n<p>Un module Top est un module un peu sp\u00e9cial en conception HDL. En effet, ce type de module se contente simplement de \u00abrelier des boites entre elles\u00bb. Ce n&rsquo;est que du tire-fils, pas besoin d&rsquo;horloge, de registres et autre structures complexes ici.<\/p>\n<p>Dans la nouvelle hi\u00e9rarchie des classes Module nous avons donc une nouvelle classe appel\u00e9e <a href=\"https:\/\/github.com\/ucb-bar\/chisel3\/pull\/469\">RawModule<\/a> qui appara\u00eet.\u00a0 Ce module n&rsquo;a plus aucun signaux implicite et se contente de relier les fils. Dans le code Chisel pr\u00e9c\u00e9dent nous pouvons juste renommer Module en RawModule pour voir que les signaux reset et clock disparaissent:<\/p>\n<pre>class Top extends RawModule {<\/pre>\n<p>Nous obtenons alors une ent\u00eate Verilog plus propre :<\/p>\n<pre>module Top(\r\n  input   io_clock_p,\r\n  input   io_clock_n,\r\n  output  io_led\r\n);<\/pre>\n<p>Nous avons tout de m\u00eame ce pr\u00e9fixe \u00abio_\u00bb disgracieux qui peu devenir p\u00e9nible pour l&rsquo;int\u00e9gration, notamment dans certaine plate-forme o\u00f9 le pinout est d\u00e9j\u00e0 fourni pour des noms de pin pr\u00e9cis.<\/p>\n<p>Il est possible de les \u00e9viter avec les RawModule simplement en utilisant plusieurs variable IO() sans Bundle :<\/p>\n<pre>class Top extends RawModule {\r\n  val clock_p = IO(Input(Clock()))\r\n  val clock_n = IO(Input(Clock()))\r\n  val led = IO(Output(Bool()))\r\n\r\n  val ibufds = Module(new IBUFDS)\r\n  ibufds.io.I := clock_p\r\n  ibufds.io.IB:= clock_n\r\n\r\n  withClockAndReset(ibufds.io.O, false.B) {\r\n    val blink = Module(new Blink)\r\n    led := blink.io.led\r\n  }\r\n}<\/pre>\n<p>De cette mani\u00e8re c&rsquo;est le nom exact de la variable qui sera pris en compte pour g\u00e9n\u00e9rer le Verilog:<\/p>\n<pre>module Top(\r\n  input   clock_p,\r\n  input   clock_n,\r\n  output  led\r\n);<\/pre>\n<p>Et voila comment nous pouvons d\u00e9sormais faire un projet proprement \u00e9crit en Chisel de A \u00e0 Z, ce qui n&rsquo;\u00e9tait pas le cas avant o\u00f9 nous \u00e9tions oblig\u00e9 d&rsquo;encapsuler le projet dans des Top.v \u00e9crit \u00e0 la main, et oblig\u00e9 de les modifier \u00e0 chaque changement d&rsquo;interface.<\/p>\n<p>Le code d\u00e9crit dans cet article se retrouve sur le <a href=\"https:\/\/github.com\/Martoni\/blp\">Blinking Led Projet,<\/a> dans le r\u00e9pertoire <a href=\"https:\/\/github.com\/Martoni\/blp\/tree\/master\/platforms\/kintex7\/chisel3\">platform<\/a>. Pour pouvoir le tester correctement, ne pas oublier de t\u00e9l\u00e9charger sa propre version de <a href=\"https:\/\/github.com\/ucb-bar\/chisel3\">Chisel3<\/a> et de merger la branche <a href=\"https:\/\/github.com\/ucb-bar\/chisel3\/tree\/modhier\">modhier<\/a> comme expliqu\u00e9 dans le <a href=\"https:\/\/github.com\/Martoni\/blp\/blob\/master\/platforms\/kintex7\/chisel3\/README.md\">README<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quelque soit le langage HDL utilis\u00e9 il est tr\u00e8s important de se garder la possibilit\u00e9 d&rsquo;int\u00e9grer des modules provenant d&rsquo;autre langages et\/ou n&rsquo;ayant pas de descriptions HDL. C&rsquo;est par exemple le cas des primitives mat\u00e9riel permettant d&rsquo;instancier des modules int\u00e9gr\u00e9s au FPGA du constructeur au moyen de \u00abtemplate\u00bb Verilog : s\u00e9rialiseur\/d\u00e9s\u00e9rialiseur, PLL, entr\u00e9es\/sorties sp\u00e9cifiques, &#8230; &hellip; <a href=\"http:\/\/www.fabienm.eu\/flf\/les-blackbox-et-rawmodule-de-chisel3\/\" class=\"more-link\">Continuer la lecture de <span class=\"screen-reader-text\">Les BlackBox et RawModule de Chisel3<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","footnotes":""},"categories":[2,4,3,20],"tags":[89,57,88,90,30,17],"class_list":["post-559","post","type-post","status-publish","format-standard","hentry","category-chisel","category-chisel-langages","category-langages","category-verilog","tag-blackbox","tag-chisel","tag-chisel3","tag-ibufds","tag-verilog","tag-xilinx"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"post-thumbnail":false},"uagb_author_info":{"display_name":"Fabien Marteau","author_link":"http:\/\/www.fabienm.eu\/flf\/author\/admin\/"},"uagb_comment_info":2,"uagb_excerpt":"Quelque soit le langage HDL utilis\u00e9 il est tr\u00e8s important de se garder la possibilit\u00e9 d&rsquo;int\u00e9grer des modules provenant d&rsquo;autre langages et\/ou n&rsquo;ayant pas de descriptions HDL. C&rsquo;est par exemple le cas des primitives mat\u00e9riel permettant d&rsquo;instancier des modules int\u00e9gr\u00e9s au FPGA du constructeur au moyen de \u00abtemplate\u00bb Verilog : s\u00e9rialiseur\/d\u00e9s\u00e9rialiseur, PLL, entr\u00e9es\/sorties sp\u00e9cifiques, &#8230;\u2026","_links":{"self":[{"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/posts\/559","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/comments?post=559"}],"version-history":[{"count":17,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/posts\/559\/revisions"}],"predecessor-version":[{"id":606,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/posts\/559\/revisions\/606"}],"wp:attachment":[{"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/media?parent=559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/categories?post=559"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.fabienm.eu\/flf\/wp-json\/wp\/v2\/tags?post=559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}