// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2003 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0

module t (
    input clk
);

  tpub p1 (
      .clk(clk),
      .i(32'd1)
  );
  tpub p2 (
      .clk(clk),
      .i(32'd2)
  );

  integer cyc;
  initial cyc = 1;
  always @(posedge clk) begin
    if (cyc != 0) begin
      cyc <= cyc + 1;
      if (cyc == 1) begin
`ifdef verilator
        $c("this->publicTop();");
`endif
      end
      if (cyc == 20) begin
        $write("*-* All Finished *-*\n");
        $finish;
      end
    end
  end

  task publicTop;
    // verilator public
    // We have different optimizations if only one of something, so try it out.
    $write("Hello in publicTop\n");
  endtask

  task test_task(input [19:0] in[2], output [19:0] out[2]);
    // Issue 3316
    // verilator public
    out[0] = in[1];
    out[1] = in[0];
  endtask

endmodule

module tpub (
    input clk,
    input [31:0] i
);

  reg [23:0] var_long;
  reg [59:0] var_quad;
  reg [71:0] var_wide;
  reg var_bool;

  // verilator lint_off BLKANDNBLK
  reg [11:0] var_flop;
  // verilator lint_on  BLKANDNBLK

  reg [23:0] got_long  /*verilator public*/;
  reg [59:0] got_quad  /*verilator public*/;
  reg [71:0] got_wide  /*verilator public*/;
  reg got_bool  /*verilator public*/;

  integer cyc;
  initial cyc = 1;
  always @(posedge clk) begin
    if (cyc != 0) begin
      cyc <= cyc + 1;
      // cyc==1 is in top level
      if (cyc == 2) begin
        publicNoArgs;
        publicSetBool(1'b1);
        publicSetLong(24'habca);
        publicSetQuad(60'h4444_3333_2222);
        publicSetWide(72'h12_5678_9123_1245_2352);
        var_flop <= 12'habe;
      end
      if (cyc == 3) begin
        if (1'b1 != publicGetSetBool(1'b0)) $stop;
        if (24'habca != publicGetSetLong(24'h1234)) $stop;
        if (60'h4444_3333_2222 != publicGetSetQuad(60'h123_4567_89ab)) $stop;
        if (72'h12_5678_9123_1245_2352 != publicGetSetWide(72'hac_abca_aaaa_bbbb_1234)) $stop;
      end
      if (cyc == 4) begin
        publicGetBool(got_bool);
        if (1'b0 != got_bool) $stop;
        publicGetLong(got_long);
        if (24'h1234 != got_long) $stop;
        publicGetQuad(got_quad);
        if (60'h123_4567_89ab != got_quad) $stop;
        publicGetWide(got_wide);
        if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
      end
      //
`ifdef VERILATOR_PUBLIC_TASKS
      if (cyc == 11) begin
        $c("this->publicNoArgs();");
        $c("this->publicSetBool(true);");
        $c("this->publicSetLong(0x11bca);");
        $c("this->publicSetQuad(0x66655554444ULL);");
        $c("this->publicSetFlop(0x321);");
        //Unsupported: $c("WData w[3] = {0x12, 0x5678_9123, 0x1245_2352}; publicSetWide(w);");
      end
      if (cyc == 12) begin
        $c("this->got_bool = this->publicGetSetBool(true);");
        $c("this->got_long = this->publicGetSetLong(0x11bca);");
        $c("this->got_quad = this->publicGetSetQuad(0xaaaabbbbccccULL);");
      end
      if (cyc == 13) begin
        $c("{ bool gb; this->publicGetBool(gb); this->got_bool=gb; }");
        if (1'b1 != got_bool) $stop;
        $c("this->publicGetLong(this->got_long);");
        if (24'h11bca != got_long) $stop;
        $c("{ uint64_t qq; this->publicGetQuad(qq); this->got_quad=qq; }");
        if (60'haaaa_bbbb_cccc != got_quad) $stop;
        $c("{ EData gw[3]; this->publicGetWide(gw); VL_ASSIGN_W(72,this->got_wide,WDataInP::external(gw)); }");
        if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
        //Below doesn't work, because we're calling it inside the loop that sets var_flop
        // if (12'h321 != var_flop) $stop;
      end
      if (cyc == 14) begin
        if ($c32("this->publicInstNum()") != i) $stop;
      end
`endif
    end
  end

  task publicEmpty;
    // verilator public
    begin
    end
  endtask

  task publicNoArgs;
    // verilator public
    $write("Hello in publicNoArgs\n");
  endtask

  task publicSetBool;
    // verilator public
    input in_bool;
    var_bool = in_bool;
  endtask

  task publicSetLong;
    // verilator public
    input [23:0] in_long;
    reg [23:0] not_long;
    begin
      not_long = ~in_long;  // Test that we can have local variables
      var_long = ~not_long;
    end
  endtask

  task publicSetQuad;
    // verilator public
    input [59:0] in_quad;
    var_quad = in_quad;
  endtask

  task publicSetFlop;
    // verilator public
    input [11:0] in_flop;
    var_flop = in_flop;
  endtask

  task publicSetWide;
    // verilator public
    input [71:0] in_wide;
    var_wide = in_wide;
  endtask

  task publicGetBool;
    // verilator public
    output out_bool;
    out_bool = var_bool;
  endtask

  task publicGetLong;
    // verilator public
    output [23:0] out_long;
    out_long = var_long;
  endtask

  task publicGetQuad;
    // verilator public
    output [59:0] out_quad;
    out_quad = var_quad;
  endtask

  task publicGetWide;
    // verilator public
    output [71:0] out_wide;
    out_wide = var_wide;
  endtask

  function publicGetSetBool;
    // verilator public
    input in_bool;
    begin
      publicGetSetBool = var_bool;
      var_bool = in_bool;
    end
  endfunction

  function [23:0] publicGetSetLong;
    // verilator public
    input [23:0] in_long;
    begin
      publicGetSetLong = var_long;
      var_long = in_long;
    end
  endfunction

  function [59:0] publicGetSetQuad;
    // verilator public
    input [59:0] in_quad;
    begin
      publicGetSetQuad = var_quad;
      var_quad = in_quad;
    end
  endfunction

  function [71:0] publicGetSetWide;
    // Can't be public, as no wide return types in C++
    input [71:0] in_wide;
    begin
      publicGetSetWide = var_wide;
      var_wide = in_wide;
    end
  endfunction

`ifdef VERILATOR_PUBLIC_TASKS
  function [31:0] publicInstNum;
    // verilator public
    publicInstNum = i;
  endfunction
`endif

endmodule
