当前位置: 首页 > news >正文

【System Verilog基础】automatic自动存储--用堆栈区存储局部变量

文章目录

    • 一、C语言的内存分配:BSS、Data、Text、Heap(堆)、Stack(栈)
      • 1、1、静态内存分配:BSS、Data
      • 1、2、程序执行代码:Text
      • 1、3、动态内存分配:Heap(堆)、Stack(栈)
      • 1、4、示例
    • 二、Verilog内存分配:静态分配、automatic自动存储
    • 三、System Verilog内存分配:静态分配、automatic自动存储
      • 3、1、举一个栗子

一、C语言的内存分配:BSS、Data、Text、Heap(堆)、Stack(栈)

  • 1、静态存储:在变量定义时就分配了固定的内存地址与内存大小并一直保持不变,直至整个程序结束;
  • 2、动态存储:由程序控制,运行时才分配内存和地址,且每次分配到的内存和地址不固定

1、1、静态内存分配:BSS、Data

  • 1、BSS段(Bss Segment):存放程序中未初始化的全局变量,属于静态内存分配
  • 2、Data段(Data Segement):存放已初始化的全局变量static声明的局部变量,属于静态内存分配

1、2、程序执行代码:Text

  • Text段(Text Segment):通常是指用来存放程序执行代码的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

1、3、动态内存分配:Heap(堆)、Stack(栈)

  • 1、Heap(堆):存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减
    • ①、堆扩张:进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上
    • ②、堆缩减利用free等函数释放内存时,被释放的内存从堆中被剔除
  • 2、Stack(栈):存放程序临时创建的局部变量(static声明的局部变量除外)、函数的参数值、返回值
    • 具有:**先进后出(FILO)**的特点,栈特别方便用来保存/恢复调用现场
    • 由系统自动分配内存,速度较快

1、4、示例

  • 一个程序本质上都是由 Bss段、Data段、Text段三个组成的。
//main.cpp
int a = 0; //data段
int a = 0; //data段
char *p1; //bss段
main() {int b; //局部变量,存放在栈中char s[] = "abc"; //局部变量,存放在栈中char *p2; //局部变量,存放在栈中char *p3 = "123456"; //123456\0在常量区,p3在栈上static int c = 0; //静态变量,data段//分配得来得10和20字节的区域就在堆区。p1 = (char *)malloc(10);p2 = (char *)malloc(20);strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

二、Verilog内存分配:静态分配、automatic自动存储

  • 1、在出现automatic之前,Verilog的所有对象都是静态分配的

    • 局部变量共用一块内存,会导致不同线程之间窜用局部变量的情况
    • 不能对任务或函数进行多次调用
  • 2、之后,可以指定任务、函数和模块使用automatic自动存储,迫使仿真器使用堆栈区存储局部变量

    • 这意味着每次调用同一个任务时,都会为其中的变量分配不同的内存和地址
  • 3、示例:

  function int auto_static_cnt(input a);int cnt = 0;  //cnt为静态存储,虽然函数调用了两次,但每次的cnt都是同一个内存cnt += a;return cnt;endfunction$display("@1 auto_static_cnt = %0d", auto_static_cnt(1)); $display("@2 auto_static_cnt = %0d", auto_static_cnt(1));//结果:虽然函数调用了两次,但每次的cnt都是同一个内存
# @1 auto_static_cnt = 1
# @2 auto_static_cnt = 2
function automatic int auto_cnt(input a);int cnt = 0; //定义为automatic后,cnt默认为automaticcnt += a;return cnt;endfunction$display("@1 auto_cnt = %0d", auto_cnt(1));$display("@2 auto_cnt = %0d", auto_cnt(1));//结果:函数调用了两次,两次的cnt分配不同的内存
# @1 auto_cnt = 1
# @2 auto_cnt = 1

三、System Verilog内存分配:静态分配、automatic自动存储

  • 1、在System Verilog中,默认也是静态存储
    • 注意!!!!!类class中定义的任务和函数是自动automatic的
    • 如果一个程序是静态的,那么所有的子程序只能共享一个内存空间,子程序的每次执行都会覆盖之前子程序运行产生的结果
  • 2、如果要使用自动存储,则必须加入automatic关键字
  • 3、如何将任务和函数声明为automatic类型
    • 显式声明:使用关键字automatic作为任务和函数声明的一部分
function automatic int auto_cnt(input a);int cnt = 0; //定义为automatic后,cnt默认为automaticcnt += a;return cnt;endfunction$display("@1 auto_cnt = %0d", auto_cnt(1));$display("@2 auto_cnt = %0d", auto_cnt(1));//结果:函数调用了两次,两次的cnt分配不同的内存
# @1 auto_cnt = 1
# @2 auto_cnt = 1
  • 隐式声明:通过将任务和函数定义在被定义为automatic类型的module, interface, program, or package中
program automatic test; //将program 声明为automatic类型function int auto_cnt(input a);int cnt = 0; //定义为automatic后,cnt默认为automaticcnt += a;return cnt;endfunction$display("@1 auto_cnt = %0d", auto_cnt(1));$display("@2 auto_cnt = %0d", auto_cnt(1));...
endprogram//结果:函数调用了两次,两次的cnt分配不同的内存
# @1 auto_cnt = 1
# @2 auto_cnt = 1
  • 4、建议将program声明为automatic类型!!!!这样其内部的任务和函数等将自动为automatic类型

3、1、举一个栗子

  • 1、automatic 加在 program 后:
program automatic test;initial begin$display("***start time is %0d", $time);  for(int i=0; i<16; i++) beginsend(i);end$display("***end time is %0d", $time);  
endtask send(int j);forkbegin$display("***Driving port %0d", j);#1;$display("***After #1 ");endjoin_none
endtaskendprogram
  • 运行结果:
***start time is 0
***end time is 0
***Driving port 0
***Driving port 1
***Driving port 2
***Driving port 3
***Driving port 4
***Driving port 5
***Driving port 6
***Driving port 7
***Driving port 8
***Driving port 9
***Driving port 10
***Driving port 11
***Driving port 12
***Driving port 13
***Driving port 14
***Driving port 15
  • 2、不加automatic:
program test;initial begin$display("***start time is %0d", $time);  for(int i=0; i<16; i++) beginsend(i);end$display("***end time is %0d", $time);  
endtask send(int j);forkbegin$display("***Driving port %0d", j);#1;$display("***After #1 ");endjoin_none
endtaskendprogram
  • 结果:
***start time is 0
***end time is 0
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
***Driving port 15
http://www.lryc.cn/news/32653.html

相关文章:

  • 看板组件:Bryntum Task Board JS 5.3.0 Crack
  • 45 个 Git 经典操作场景,专治不会合代码
  • MyBatis之动态SQL
  • SpringBoot(Tedu)—DAY01——环境搭建
  • 代理模式-大话设计模式
  • STM32定时器的编码器接口模式
  • Java方法的使用
  • Linux命令·nl
  • 排序模型:DIN、DINE、DSIN
  • 【C++】Clang-Format:代码自动格式化(看这一篇就够了)
  • Linux命令·more
  • 为什么 SaaS 公司依靠知识库来做对客户服务?
  • 后端必备之VUE基础【黑马程序员】
  • 现代HYUNDAI EDI需求分析
  • 数据库基本功之SQL的基本函数
  • 配置主机名与ip的映射关系
  • Spring Cache简单介绍和使用
  • ECCV 2022|面向精确的主动相机定位算法
  • web实现环形旋转、圆形、弧形、querySelectorAll、querySelector、clientWidth、sin、cos、PI
  • PyCharm+Python+Selenium自动化测试动态验证码识别
  • git版本回退简单记录
  • QT入门Display Widgets之QLine、QLcdNumber、QTextBrowser
  • Spring学习笔记
  • 数据的标准化处理
  • 性能优化|记一次线上OOM问题处理
  • Vue动态粒子特效插件(背景线条吸附动画)
  • 【Java 类】002-类、属性、方法、代码块
  • Ubuntu Linux 编译安装的基本步骤
  • day59反刍笔记
  • 【阅读笔记】你不知道的Javascript--强制类型转换4