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

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

【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