{"id":1941,"date":"2025-08-07T09:27:03","date_gmt":"2025-08-07T09:27:03","guid":{"rendered":"https:\/\/dsd.webs.upv.es\/?page_id=1941"},"modified":"2025-08-07T09:30:27","modified_gmt":"2025-08-07T09:30:27","slug":"guia-completa-de-clocking-blocks-en-uvm","status":"publish","type":"page","link":"https:\/\/dsd.webs.upv.es\/?page_id=1941","title":{"rendered":"Uso combinado interfaz y  Clocking Blocks en UVM"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Esta gu\u00eda explica el papel fundamental de los <strong>clocking blocks<\/strong> de SystemVerilog en la construcci\u00f3n de entornos de verificaci\u00f3n robustos bajo la Metodolog\u00eda de Verificaci\u00f3n Universal (UVM). Cubriremos desde los conceptos b\u00e1sicos hasta las mejores pr\u00e1cticas para la sincronizaci\u00f3n, el manejo de datos y la cobertura funcional.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">El Problema: Las Condiciones de Carrera<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">En la verificaci\u00f3n, el entorno de prueba (Testbench) y el Dise\u00f1o Bajo Prueba (DUT) se ejecutan en paralelo. Si ambos intentan leer y escribir en la misma se\u00f1al en el mismo instante (por ejemplo, en un flanco de reloj), el resultado es impredecible. Esto se conoce como <strong>condici\u00f3n de carrera<\/strong> (<em>race condition<\/em>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u00bfQu\u00e9 valor lee el testbench? \u00bfEl antiguo o el nuevo?<\/strong> La respuesta depende del orden interno en que el simulador ejecute los procesos, lo que hace que la simulaci\u00f3n no sea determinista y, por tanto, no sea fiable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">La Soluci\u00f3n: \u00bfQu\u00e9 es un Clocking Block?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un <strong>clocking block<\/strong> es una construcci\u00f3n de SystemVerilog que agrupa un conjunto de se\u00f1ales y define de forma estricta c\u00f3mo y cu\u00e1ndo deben ser le\u00eddas (muestreadas) o escritas (conducidas) en relaci\u00f3n con un evento de reloj espec\u00edfico.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Su objetivo principal es <strong>eliminar las condiciones de carrera<\/strong> introduciendo m\u00e1rgenes de seguridad temporales.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sintaxis y Componentes Clave<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\n\/\/ Definido dentro de una interface\ninterface mi_if(input bit clk);\n  logic        req;\n  logic        gnt;\n  logic &#x5B;7:0]  data;\n\n  \/\/ El clocking block define la temporizaci\u00f3n desde la perspectiva del Testbench\n  clocking tb_cb @(posedge clk);\n    \/\/ Margen de seguridad por defecto para entradas y salidas\n    default input #1step output #2ns;\n\n    \/\/ Direcci\u00f3n de las se\u00f1ales desde el punto de vista del TB\n    input   gnt;\n    output  req, data;\n  endclocking: tb_cb\n\nendinterface\n\n<\/pre><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li><code>@(posedge clk)<\/code>: Especifica el evento de reloj que gobierna el bloque.<\/li>\n\n\n\n<li><code>default input #1step<\/code>: <strong>Skew de Entrada<\/strong>. Muestrea las se\u00f1ales de entrada un paso de simulaci\u00f3n infinitesimal (<code>1step<\/code>) <strong>antes<\/strong> del flanco de reloj. Esto garantiza que se lea el valor estable del ciclo anterior.<\/li>\n\n\n\n<li><code>default output #2ns<\/code>: <strong>Skew de Salida<\/strong>. Conduce las se\u00f1ales de salida 2 nanosegundos <strong>despu\u00e9s<\/strong> del flanco de reloj. Esto da tiempo al DUT a muestrear los valores actuales antes de que el testbench los cambie.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Aplicaci\u00f3n Pr\u00e1ctica en UVM: Driver y Monitor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Los <code>clocking blocks<\/code> son la pieza central para la sincronizaci\u00f3n en los componentes UVM que interact\u00faan directamente con el DUT.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">El Driver: Conducci\u00f3n Segura de Se\u00f1ales<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El driver conduce transacciones hacia el DUT. Usa el clocking block para asegurarse de que lo hace sin conflictos.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Sincronizaci\u00f3n:<\/strong> Espera al evento del clocking block con <code>@(vif.tb_cb)<\/code>.<\/li>\n\n\n\n<li><strong>Asignaci\u00f3n:<\/strong> Utiliza asignaciones <strong>no bloqueantes (<code>&lt;=<\/code>)<\/strong> para imitar el comportamiento concurrente de los registros en el hardware.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nclass my_driver extends uvm_driver #(my_transaction);\n  \/\/ ... (c\u00f3digo uvm boilerplate) ...\n  virtual task run_phase(uvm_phase phase);\n    forever begin\n      \/\/ 1. Obtener la transacci\u00f3n a enviar\n      seq_item_port.get_next_item(req);\n\n      \/\/ 2. Sincronizarse con el reloj a trav\u00e9s del clocking block\n      @(vif.tb_cb);\n\n      \/\/ 3. Conducir las se\u00f1ales usando asignaciones NO bloqueantes\n      \/\/ El skew de salida se aplica autom\u00e1ticamente\n      vif.tb_cb.req  &lt;= 1;\n      vif.tb_cb.data &lt;= req.data;\n\n      \/\/ Esperar a la respuesta (grant) del DUT\n      wait (vif.tb_cb.gnt == 1);\n      \n      @(vif.tb_cb);\n      vif.tb_cb.req &lt;= 0;\n\n      \/\/ 4. Notificar que la transacci\u00f3n ha finalizado\n      seq_item_port.item_done();\n    end\n  endtask\nendclass\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">El Monitor: Muestreo Fiable del Bus<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El monitor observa el bus y convierte la actividad de las se\u00f1ales en objetos de transacci\u00f3n.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Sincronizaci\u00f3n:<\/strong> Tambi\u00e9n espera al evento <code>@(vif.tb_cb)<\/code>.<\/li>\n\n\n\n<li><strong>Asignaci\u00f3n:<\/strong> Utiliza asignaciones <strong>bloqueantes (<code>=<\/code>)<\/strong> para capturar los valores muestreados en variables locales de forma inmediata.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nclass my_monitor extends uvm_monitor;\n  uvm_analysis_port #(my_transaction) analysis_port;\n  \/\/ ... (c\u00f3digo uvm boilerplate) ...\n\n  virtual task run_phase(uvm_phase phase);\n    forever begin\n      \/\/ 1. Sincronizarse con el reloj\n      @(vif.tb_cb);\n\n      \/\/ 2. Comprobar si hay una transacci\u00f3n v\u00e1lida para muestrear\n      \/\/ El skew de entrada ya ha garantizado que leemos valores estables\n      if (vif.tb_cb.req &amp;&amp; vif.tb_cb.gnt) begin\n        my_transaction trans = my_transaction::type_id::create(&quot;trans&quot;);\n\n        \/\/ 3. Capturar los valores usando asignaciones BLOQUEANTES\n        trans.data = vif.tb_cb.data;\n\n        \/\/ 4. Enviar la transacci\u00f3n capturada para su an\u00e1lisis\n        analysis_port.write(trans);\n      end\n    end\n  endtask\nendclass\n\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Cobertura Funcional: El Enfoque UVM<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un error com\u00fan es vincular la cobertura a un evento de reloj. La filosof\u00eda UVM dicta que la cobertura debe ser <strong>impulsada por la transacci\u00f3n<\/strong>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pr\u00e1ctica Recomendada <\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Se crea un componente suscriptor (o se usa el scoreboard) que recibe la transacci\u00f3n del monitor y entonces, y solo entonces, muestrea la cobertura.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nclass my_coverage_subscriber extends uvm_subscriber #(my_transaction);\n\n  \/\/ Covergroup que se muestrea con una transacci\u00f3n como argumento\n  covergroup data_cg with function sample(my_transaction t);\n    coverpoint t.data {\n      bins ZEROS = {0};\n      bins ONES  = {&#039;1};\n      bins OTHER = default;\n    }\n  endgroup\n\n  function new(string name, uvm_component parent);\n    super.new(name, parent);\n    data_cg = new();\n  endfunction\n\n  \/\/ Esta funci\u00f3n se ejecuta autom\u00e1ticamente cuando el monitor llama a analysis_port.write()\n  virtual function void write(my_transaction t);\n    \/\/ El momento perfecto para muestrear: tenemos una transacci\u00f3n completa y validada.\n    data_cg.sample(t);\n  endfunction\n\nendclass\n\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Pr\u00e1ctica Desaconsejada <\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Definir un <code>covergroup<\/code> con un trigger de reloj (<code>covergroup cg @(posedge clk);<\/code>) rompe la abstracci\u00f3n, ya que vuelve a acoplar la l\u00f3gica de cobertura al hardware, ignorando la capa de transacciones y arriesg\u00e1ndose a muestrear datos en momentos incorrectos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusi\u00f3n: Principios Clave<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Usa Clocking Blocks Siempre:<\/strong> Son la herramienta est\u00e1ndar para la sincronizaci\u00f3n segura entre el testbench y el DUT.<\/li>\n\n\n\n<li><strong>Abstrae la Temporizaci\u00f3n:<\/strong> Define la temporizaci\u00f3n una sola vez en la <code>interface<\/code>. El resto del entorno de prueba simplemente se sincroniza con el evento del clocking block.<\/li>\n\n\n\n<li><strong>Respeta las Asignaciones:<\/strong> Usa <strong>no bloqueantes (<code>&lt;=<\/code>) en el Driver<\/strong> para conducir se\u00f1ales y <strong>bloqueantes (<code>=<\/code>) en el Monitor<\/strong> para capturar valores.<\/li>\n\n\n\n<li><strong>Impulsa la Cobertura por Transacciones:<\/strong> Muestrea tus <code>covergroups<\/code> llamando expl\u00edcitamente a <code>.sample()<\/code> cuando recibas una transacci\u00f3n, no con triggers de reloj.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Esta gu\u00eda explica el papel fundamental de los clocking blocks de SystemVerilog en la construcci\u00f3n de entornos de verificaci\u00f3n robustos bajo la Metodolog\u00eda de Verificaci\u00f3n Universal (UVM). Cubriremos desde los conceptos b\u00e1sicos hasta las mejores pr\u00e1cticas para la sincronizaci\u00f3n, el manejo de datos y la cobertura funcional. El Problema: Las Condiciones de Carrera En la verificaci\u00f3n, el entorno de prueba (Testbench) y el Dise\u00f1o Bajo Prueba (DUT) se ejecutan en paralelo. Si ambos intentan leer y escribir en la misma se\u00f1al en el mismo instante (por ejemplo, en un flanco de reloj), el resultado es impredecible. Esto se conoce como condici\u00f3n de carrera (race condition). \u00bfQu\u00e9 valor lee el testbench? \u00bfEl antiguo o el nuevo? La respuesta depende del orden interno en que el simulador ejecute los procesos, lo que hace que la simulaci\u00f3n no sea determinista y, por tanto, no sea fiable. La Soluci\u00f3n: \u00bfQu\u00e9 es un Clocking Block? Un clocking block es una construcci\u00f3n de SystemVerilog que agrupa un conjunto de se\u00f1ales y define de forma estricta c\u00f3mo y cu\u00e1ndo deben ser le\u00eddas (muestreadas) o escritas (conducidas) en relaci\u00f3n con un evento de reloj espec\u00edfico. Su objetivo principal es eliminar las condiciones de carrera introduciendo m\u00e1rgenes de seguridad temporales. Sintaxis y Componentes Clave Aplicaci\u00f3n Pr\u00e1ctica en UVM: Driver y Monitor Los clocking blocks son la pieza central para la sincronizaci\u00f3n en los componentes UVM que interact\u00faan directamente con el DUT. El Driver: Conducci\u00f3n Segura de Se\u00f1ales El driver conduce transacciones hacia el DUT. Usa el clocking block para asegurarse de que lo hace sin conflictos. El Monitor: Muestreo Fiable del Bus El monitor observa el bus y convierte la actividad de las se\u00f1ales en objetos de transacci\u00f3n. Cobertura Funcional: El Enfoque UVM Un error com\u00fan es vincular la cobertura a un evento de reloj. La filosof\u00eda UVM dicta que la cobertura debe ser impulsada por la transacci\u00f3n. Pr\u00e1ctica Recomendada Se crea un componente suscriptor (o se usa el scoreboard) que recibe la transacci\u00f3n del monitor y entonces, y solo entonces, muestrea la cobertura. Pr\u00e1ctica Desaconsejada Definir un covergroup con un trigger de reloj (covergroup cg @(posedge clk);) rompe la abstracci\u00f3n, ya que vuelve a acoplar la l\u00f3gica de cobertura al hardware, ignorando la capa de transacciones y arriesg\u00e1ndose a muestrear datos en momentos incorrectos. Conclusi\u00f3n: Principios Clave<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","ub_ctt_via":"","footnotes":""},"class_list":["post-1941","page","type-page","status-publish","hentry"],"featured_image_src":null,"_links":{"self":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/1941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1941"}],"version-history":[{"count":3,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/1941\/revisions"}],"predecessor-version":[{"id":1945,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/1941\/revisions\/1945"}],"wp:attachment":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}