⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cordic_par_seq_apb_test_master_rtl.v

📁 systemverilog程序
💻 V
字号:
`timescale 1ns/1ns

module CORDIC_par_seq_bus_test_master_RTL

  #(parameter
      period = 10,
      master_Tco = 2
  )
  (
    APB.RTL_master apb,
    output logic  async_reset
  );

  always begin: ClockGenerator
    apb.PCLK = 0;
    apb.PCLK <= #(period/2) 1;
    #period;
  end // ClockGenerator

// _____________________________________________________ BFM ENTRY POINTS ___

  // Non-synthesisable task-call interface for a testbench master
  // so that it can exercise slaves on the bus without the need for
  // a fully-functional model of a master device.

  // Call these BFM tasks at the posedge of the clock right
  // at the beginning of the cycle. They return just after
  // the final posedge of the cycle.


  // ______________________________________________________ reset() ___
  //
  task reset ( int n );
    async_reset = 1;
    idle(n);
    ClockTcoSync;
    async_reset = 0;
  endtask // reset


  // _______________________________________________________ read() ___
  //
  task read (
    input  T_APB_a adrs,
    output T_APB_d data
  );

    // Get to Tco after the most recent possible clock
    ClockTcoSync;
      apb.PADDR    = adrs;
      apb.PWRITE   = 1'b0;
      apb.psel     = 1'b1;

    @(posedge apb.PCLK)
      apb.PENABLE <= #master_Tco 1'b1;

    @(posedge apb.PCLK)
      data     = apb.PRDATA;
      apb.PADDR   <= {$bits(apb.PADDR){1'bx}};
      apb.psel    <= 1'b0;
      apb.PENABLE <= 1'b0;

  endtask // read


  // ______________________________________________________ write() ___
  //
  task write (
    input T_APB_a adrs,
    input T_APB_d data
  );

    // Get to Tco after the most recent possible clock
    ClockTcoSync;
      apb.PADDR    = adrs;
      apb.PWDATA   = data;
      apb.PWRITE   = 1'b1;
      apb.psel     = 1'b1;

    @(posedge apb.PCLK)
      apb.PENABLE <= #master_Tco 1'b1;

    @(posedge apb.PCLK)
      apb.PWDATA  <= {$bits(apb.PADDR){1'bx}};
      apb.PADDR   <= {$bits(apb.PADDR){1'bx}};
      apb.psel    <= 1'b0;
      apb.PENABLE <= 1'b0;

  endtask // write


  // _______________________________________________________ idle() ___
  //
  task idle ( int n );

    if (n > 0 ) begin
      // Get to Tco after the most recent possible clock
      ClockTcoSync;
      repeat (n) @(posedge apb.PCLK);
    end

  endtask


// __________________________________________________________________________



// ____________________________________________ HELPER CODE FOR BFM TASKS ___

  // As always with procedural entry points into a BFM, there is
  // an issue about synchronisation between the moment of task call
  // and the bus's clock.  If the task is called at some random time,
  // its activity must be resynchronised to the bus clock.  However,
  // if it's already synchronised, then we don't want a spurious
  // additional clock wait.  One possible solution to this problem is
  // offered here: the BFM read and write tasks can be called at any
  // time.  If called at or just after a clock edge, BFM activity can
  // proceed as from that clock edge (signals don't need to be set up
  // until one clock-to-valid delay after the clock edge).  If called
  // at any other time, the task is stalled until just after the next
  // clock edge.

  // In order to make this approach work, we need to keep track of
  // the time of the most recent active clock edge.
  //
  always @(posedge apb.PCLK) begin : ClockEdgeLogger

    time LastClock;
    LastClock = $time;

  end // ClockEdgeLogger

  // Now, when a BFM task is called, it uses the time-of-last-clock
  // information to determine whether it can proceed immediately, or
  // must wait until the next clock.  Task ClockTcoSync encapsulates
  // this behaviour;  it not only enforces the clock wait if necessary,
  // but also waits until the future time at which the BFM task must
  // apply its valid bus signals.
  //
  // Note that this task will still work correctly even if
  // parameter master_Tco is set to zero.
  //
  task ClockTcoSync;

    time t;

    // If this task was called as the result of a clock edge, we must
    // be sure that the LastClock value has already been updated.
    // That's why we need a #0 delay prefix here.
    //
    #0 t = $time - ClockEdgeLogger.LastClock;

    // Are we too late to start the bus cycle on the current clock?
    //
    if (t > master_Tco) begin

      // Yes, we're too late.  Wait for the next clock.
      @(posedge apb.PCLK) t = master_Tco;

    end else begin

      // No, we're in time.  Calculate how long we need to wait
      // before applying the right signals.
      t = master_Tco - t;

    end

    // Finally, align to Tco after the chosen clock
    #(t);

  endtask

endmodule // CORDIC_par_seq_bus_test_master_RTL

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -