在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 4157|回复: 24

[求助] $fopen(fh, ...)在$fclose(fh)前不能将内容写到文件中去

[复制链接]
发表于 2023-3-9 23:22:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
uvm验证中使用$fopen(fh, “a.log")打开一个文件并往其中写入信息,但是在仿真结束前中断了仿真导致$fclose(fh)没有执行到,发现对应a.log中没有任何内容,该怎么解决这个问题?

发表于 2023-3-10 09:10:38 | 显示全部楼层
你说的是没有成功写入嘛
发表于 2023-3-10 09:15:06 | 显示全部楼层
是不是可以试着打印一下句柄,看看文件是否被成功打开
发表于 2023-3-10 11:12:31 | 显示全部楼层
在这种情况下,你可以通过在 UVM 中使用相应的事件来控制文件关闭操作的执行。

在你使用$fopen()函数打开文件之前,你可以创建一个事件对象并将其关联到文件对象。创建事件的语法如下所示:
event e_close;
然后使用-ve选项关联该事件到文件对象中,以便文件对象可以等待该事件执行完毕后再执行$fclose()函数。关联事件的语法如下所示:
fh.set_sv_flag(UVM_FILE | UVM_FILE_CLOSE_ON_STOP | UVM_FILE_OVERWRITE);
fh.set_sv_close_on_stop(1);
fh.set_sv_close_flag(e_close, UVM_FCLOSE_E_AFTER_BLOCK);
以上语句中,UVM_FILE_CLOSE_ON_STOP选项要求在仿真停止时关闭文件,并使用set_sv_close_on_stop(1)来启用该选项。然后,使用set_sv_close_flag()函数将事件对象关联到文件对象中,以便在仿真结束时关闭文件。

当仿真结束后,可以使用以下代码来触发事件以执行文件关闭操作:
e_close.trigger();
这样,无论的仿真过程是否被中断,都可以确保文件正常地被关闭,且文件中包含有关仿真执行的完整信息。

-----------------------------------------------------
以上是ChatGPT的回答,尚未经过验证,你可以试一下
发表于 2023-3-10 11:14:11 | 显示全部楼层
ChatGPT关于set_sv_flag()函数的解释:

set_sv_flag()函数是UVM库中的一个函数,用于设置文件对象的选项和标志。该函数有两个参数,第一个参数是一个标志和一个可选的scope,第二个参数是一个值,表示需要设置的选项或标志。其中,scope指定了设置的作用域,可以是文件、行、测试、组件、顶层测试等作用域。

对于文件对象来说,set_sv_flag()函数支持以下几种标志:

UVM_FILE_AUTOMATIC_RECORD:当设置该标志时,在文件对象中发生的每个写操作都会自动记录状态,并在文件关闭时自动写回文件。这可以确保写操作的一致性,但当需要以最佳性能方式打开文件时可能会影响性能。

UVM_FILE_BLOCKING:当设置该标志时,写操作将是阻塞的。这意味着写操作不会立即完成,而是等待系统将所有输出写入设备后再返回。这在需要确保数据完整性的场合中非常有用。

UVM_FILE_NONBLOCKING:当设置该标志时,写操作将是非阻塞的。这意味着写操作调用后立即返回,而写操作将在后台进行。

UVM_FILE_OVERWRITE:当设置该标志时,文件将被覆盖。这意味着如果文件已存在,则文件中原有的数据将被删除。如果文件不存在,则文件将被创建。

UVM_FILE_APPEND:当设置该标志时,将会向文件的末尾追加写入数据,而不会覆盖原有数据。如果文件不存在,则文件将被创建。

UVM_FILE_NO_PATH:当设置该标志时,文件路径中的目录信息将被忽略,即使路径中存在目录也不会尝试在该目录中创建文件。这在需要创建多个文件时非常有用,因为您可以不必显式地为每个文件创建目录。

UVM_FILE_NO_CONSOLE:当设置该标志时,标准输出和标准错误被禁用,并且数据不会输出到控制台。

UVM_FILE_CLOSE_ON_STOP:当设置该标志时,文件将在仿真结束时自动关闭。

对于flag中的值,可以使用按位或运算符组合多个标志。例如:fh.set_sv_flag(UVM_FILE | UVM_FILE_CLOSE_ON_STOP | UVM_FILE_OVERWRITE)中,使用“|”组合了3个标志。
发表于 2023-3-10 11:16:23 | 显示全部楼层
ChatGPT关于set_sv_close_flag的解释:

set_sv_close_flag()函数是UVM库中的一个函数,用于将事件对象关联到文件对象中。该函数有三个参数:

第一个参数是一个事件对象,用于指定在何种情况下执行文件关闭操作。
第二个参数是一个标志,用于指定在执行文件关闭操作时文件对象的行为。
第三个参数是一个可选的scope,用于指定设置的作用域。
对于文件对象来说,set_sv_close_flag()函数支持以下几种标志:

UVM_FCLOSE_NONE:该标志表示文件将始终保持打开状态,不会在执行仿真完毕时关闭。

UVM_FCLOSE_E_BLOCK:该标志表示文件对象将在事件触发时关闭。也就是说,当事件已经触发并且所关联的进程已经执行完成时,文件对象将自动关闭。

UVM_FCLOSE_E_AFTER_BLOCK:该标志表示文件对象将在事件触发后关闭。也就是说,当事件已经触发时,文件对象将等待所关联的进程执行完成后关闭。

UVM_FCLOSE_E_AT_BLOCK:该标志表示文件对象将在事件触发时立即关闭,而不管事件关联的进程是否执行完成。

当您使用set_sv_close_flag()函数将事件与文件对象关联时,您需要确保事件对象可以在仿真停止时被触发。否则,文件对象将无法正常关闭。因此,您可以在run_phase中使用以下代码块来等待仿真停止时触发事件对象:
task run_phase(uvm_phase phase);
  phase.raise_objection(this);
  // 等待仿真停止时触发事件对象
  e_close.wait_trigger();
  phase.drop_objection(this);
endtask : run_phase
当仿真结束时,事件对象将被触发,并执行文件关闭操作,确保数据被正确写入文件中。
发表于 2023-3-10 11:31:41 | 显示全部楼层
以下是和ChatGPT的另一种回答,以及相应的讨论,觉得挺有意思,一并贴出来:

在UVM中,我们可以使用UVM的Phasing机制中的teardown阶段来确保所有资源都得到清理和释放。具体来说,我们可以将Phasing机制中的teardown阶段用于关闭文件并完成文件写操作。

在test结束前,我们可以通过以下方式将teardown阶段添加到Phasing序列中:

task run_phase(uvm_phase phase);
  phase.raise_objection(this);
  phase.exec_seq_item(new initial_seq());
  phase.drop_objection(this);
endtask

class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    phase.exec_seq_item(new my_seq());
    phase.drop_objection(this);
  endtask

  task final_phase(uvm_phase phase);
    $fclose(fh); // 关闭文件
  endtask

endclass

module top_module;
  // ...
  initial begin
  uvm_config_db #(virtual my_env)::set(null, "tb.env", "default_env", new());
  run_test();
  end
  // ...

  task run_test();
    uvm_root uvm_root_inst;
    uvm_root_inst = uvm_root::get();
    uvm_run_test();
    uvm_report_info("MY_ENV_TEARDOWN", "Executing my_env teardown.", UVM_NONE);
    uvm_root_inst.phase_process("my_env.teardown_phase");
  endtask

endmodule
在上述代码中,我们为my_env环境添加了一个final_phase任务,其中我们可以在其中添加文件关闭操作。另外,我们在run_test任务中添加了uvm_root_inst.phase_process("my_env.teardown_phase")语句,这将在仿真结束前执行my_env环境中的teardown_phase。

通过这种方式,我们可以确保在仿真结束时,文件已经被正确地关闭并且数据成功写入a.log中。
发表于 2023-3-10 11:33:09 | 显示全部楼层
问:这种方法,能保证仿真在异常中断退出的情况下,文件被正确地写入到a.log里面吗?

答:
如果仿真在异常中断退出,可能无法保证所有的资源和操作都得到正确的清理和释放。因此,在这种情况下,您可能无法保证文件已经被正确地写入到a.log中。

为了避免这种情况,您可以定期手动调用$fclose(fh)函数,以确保文件写操作得到及时的完成。或者,您可以通过UVM的回收机制来自动处理一些资源并确保在异常退出时,所有的操作都得到正确地清理和释放。在这种情况下,您可以将文件写操作放在UVM的回收机制中,以确保每次操作均被正确地执行。

举一个例子,您可以创建一个名为my_file_writer的类,这个类负责打开文件并写入数据。在phase_started()方法中,您可以将my_file_writer类添加到UVM的回收机制中,以确保每次操作均被正确地执行。而在phase_ended()方法中,您可以将my_file_writer类从UVM的回收机制中移除,并手动调用$fclose(fh)函数,以确保文件已经被正确地关闭和写入。

class my_file_writer extends uvm_object;
  string filename;
  bit [$] data;

  function new(string name="");
    super.new(name);
  endfunction

  function void open(string filename);
    this.filename = filename;
    fh = $fopen(filename, "a");
  endfunction

  function void write(bit [$] data);
    this.data = data;
    $fwrite(fh, "%s\n", this.data);
  endfunction

endclass

class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  my_file_writer my_writer;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    my_writer = new("my_writer");
  endfunction

  function void phase_started(uvm_phase phase);
    super.phase_started(phase);
    if(phase.get_name() == "run") begin
      my_writer.open("a.log");
      uvm_hdl_add_objection(this, my_writer);
    end
  endfunction

  function void phase_ended(uvm_phase phase);
    if(phase.get_name() == "run") begin
      uvm_hdl_remove_objection(this, my_writer);
      $fclose(my_writer.fh);
    end
    super.phase_ended(phase);
  endfunction

endclass
在上述代码中,我们将my_file_writer类添加到了UVM回收机制中,以确保每次操作都得到正确地执行。而在phase_ended()方法中,我们将my_file_writer类从UVM回收机制中移除,并手动调用$fclose(fh)函数以确保文件被正确地关闭和写入。

通过这种方式,即可确保在异常退出的情况下,文件已经被正确地写入到a.log中。
发表于 2023-3-10 11:34:28 | 显示全部楼层
问:phase_started是什么函数?具体是指哪个phase?
答:
phase_started(phase)是UVM中的一个Task,用于在某个Phase开始时执行。当UVM中的某个Phase启动时,UVM会自动调用每个组件对应的phase_started(phase)方法,以让组件有机会在Phase开始前执行一些前置操作,例如初始化某些资源、创建对象等。

UVM中的Phase是一种事件驱动的机制,用于组织不同的仿真阶段。UVM中有一些预定义的Phase,包括:build,connect,run,extract,check,report,final等,不同的Phase对应着不同的仿真阶段。在UVM中,我们也可以定义自己的Phase,并使用Phasing机制将不同的Phase按照顺序连接在一起。

因此,phase_started(phase)方法中的phase参数指的是当前启动的Phase,可以使用phase.get_name()方法来获取当前Phase的名称,从而执行不同的操作。

在上面的例子中,我们使用phase_started(phase)方法中的phase参数来判断是否进入了run阶段,如果是则调用my_writer对象的open()方法打开文件,并将my_writer对象添加到UVM的回收机制中。
发表于 2023-3-10 11:36:05 | 显示全部楼层
问:如果仿真异常退出了,还会调用phase_ended()函数吗?
答:
如果仿真异常退出,很可能不会再执行任何UVM内部的代码,包括phase_ended(phase)方法。因此,当发生异常退出时,phase_ended(phase)方法可能无法被执行。这也是为什么需要手动调用$fclose(fh)函数以确保文件被正确地关闭和写入。

此外,在UVM中,可以通过UVM的Catch mechanism机制来处理一些异常情况,例如系统崩溃、断电等。UVM的Catch mechanism机制可以在异常情况发生时执行一些特定的操作或自定义回调函数,以确保仿真环境的稳定性和安全性。在这种情况下,您可以使用UVM的Catch mechanism机制来处理异常退出,并在自定义的Callback函数中调用$fclose(fh)函数以确保文件被正确地关闭和写入。

以下是一个使用UVM的Catch mechanism机制的例子:

class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  my_file_writer my_writer;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    my_writer = new("my_writer");
  endfunction

  function void phase_started(uvm_phase phase);
    super.phase_started(phase);
    if(phase.get_name() == "run") begin
      my_writer.open("a.log");
      uvm_hdl_add_objection(this, my_writer);
    end
  endfunction

  function void phase_ended(uvm_phase phase);
    if(phase.get_name() == "run") begin
      uvm_hdl_remove_objection(this, my_writer);
      $fclose(my_writer.fh);
    end
    super.phase_ended(phase);
  endfunction

  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    uvm_report_info("MY_ENV_CONNECT", "Setting up my_env connect phase.", UVM_NONE);
    $catch("my_caught_error", {`MY_CAUGHT_ERROR}, my_callback);
  endfunction

  function void my_callback();
    $fclose(my_writer.fh);
  endfunction

endclass
在上述代码中,我们在connect_phase(phase)方法中使用了UVM的Catch mechanism机制,当定义的$catch表达式中的条件为真(MY_CAUGHT_ERROR)时,会调用my_callback()方法,即手动调用$fclose(fh)函数以确保文件被正确地关闭和写入。

请注意,您需要在具体的仿真环境中根据实际情况来定义MY_CAUGHT_ERROR条件,并根据具体的异常情况来在my_callback()方法中执行相应的操作。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条

小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-9-23 17:22 , Processed in 0.020756 second(s), 7 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表