YAMM概述
另一个内存管理器(YAMM)是一个SystemVerilog库,为基于内存的操作提供支持,由Ionut Tolea和Andrei Vintila在2016年慕尼黑SNUG会议上发表了论文“另一个内存管理器”(YAMM):- 缓冲区可以按照任何粒度或地址对齐的6种分配模式进行分配
- 缓冲区可以由用户插入(非重叠)
- 缓冲区可以通过地址或句柄来解除分配
- 缓冲区可以通过地址或句柄在内存空间中搜索
- 缓冲区支持有效载荷,可以由用户分配,随机生成,读取和比较。
- 实现快速缓冲区搜索算法
除了这些功能之外,YAMM还提供调试功能(例如,内存镜像存储,使用情况统计),并且很容易将其与现有验证环境集成。
基本概念
存储器映射的空间由起始地址和大小来标识的。同样,缓冲区是由起始地址和大小定义的连续地址空间。有两种类型的缓冲区:
- 空闲缓冲区:可用于进一步分配/插入用户缓冲区
- 用户缓冲区:用户分配的空间
内存映射被初始化为一个空闲缓冲区。要使用内存中的特定区域,您必须分配非0大小的缓冲区。通过在内存中分配缓冲区,初始空闲缓冲区被拆分并调整大小,以便为新缓冲区腾出空间,如下例所示。
取消分配缓冲区是分配的逆操作。取消分配用一个空闲缓冲区替换一个用户缓冲区; YAMM检查是否有相邻的空闲缓冲区并将它们合并到单个空闲缓冲区中以最小化空闲缓冲区列表。
YAMM提供了两个启用内存管理功能的类:
- yamm_buffer:实现缓冲区特定功能的基类
- yamm:继承yamm_buffer并实现内存映射的特定功能
在结构上,YAMM将存储器映射作为一个空闲和占用缓冲区链处理,并作为两个双链表进行管理(请参阅下图):
- 所有缓冲区列表:链接内存中的所有缓冲区
- 空闲缓冲区列表:只链接空闲缓冲区
用法示例
以下部分将通过示例介绍YAMM的API,以便对YAMM功能有基本的了解。另外,作为新用户,您应该查看yamm_tutorial.sv示例。
初始化
通过实例化yamm对象并调用build()函数来定义内存映射。在这个阶段,内存有一个名字和一个大小,并且包含一个可以延伸整个内存空间的空闲缓冲区。
import yamm_pkg::*;
// Instantiate a memory map
automatic yamm mem = new;
// Initialize the memory map space to 1MByte and set it's name to YAMM_MEMORY_MAP
mem.build("YAMM_MEMORY_MAP", 1024*1024);
缓冲区操作:插入,分配,取消分配
初始化后,可以使用其中一种分配方法(allocate(),allocate_by_size())分配缓冲区。内存管理器将搜索适当的空闲缓冲区来保存所需的内存空间(即空闲缓冲区的大小足以容纳分配的缓冲区)。搜索空闲缓冲区将考虑分配模式:- RANDOM_FIT - 随机空闲缓冲区,适合请求的内存空间,在空闲缓冲区内选择一个随机地址
- FIRST_FIT - 第一个适合请求的内存空间的空闲缓冲区,在空闲缓冲区中选择第一个地址
- BEST_FIT - 适合请求的内存空间的最小空闲缓冲区,在空闲缓冲区内选择第一个地址
- UNIFORM_FIT - 适合请求的内存空间的最大空闲缓冲区,适用于空闲空间中间的已分配缓冲区
- FIRST_FIT_RANDOM - 第一个适合请求的内存空间的空闲缓冲区,选择空闲缓冲区内的随机地址
- BEST_FIT_RANDOM - 适合请求的内存空间的最小空闲缓冲区,在空闲缓冲区内选择随机地址
在下面的代码框中,您可以看到有关缓冲区分配的几个示例:
// declare a yamm_buffer variable
yamm_buffer a_buffer = new;
a_buffer.size = 256;
assert(mem.allocate(a_buffer, RANDOM_FIT)) else `uvm_warning("APB_SEQ", "Can not insert the desired buffer!");
a_buffer.set_name("A_Buffer");
........................
// allocate by size
yamm_buffer x_buffer = mem.allocate_by_size(256, RANDOM_FIT);
assert(x_buffer != null) else `uvm_error("APB_SEQ", "Can not insert the desired buffer!");
x_buffer.set_name("X_Buffer");
通过使用其中一种插入方法(例如insert(),insert_by_access()),也可以将缓冲区“手动”插入特定地址。在这种情况下,内存管理器将只检查给定地址是否有足够的空间并执行缓冲区插入。
yamm_buffer a_buffer = new;
a_buffer.set_name("A_Buffer");
a_buffer.size = 256;
a_buffer.start_addr = 'hCAFE1001;
// insert() function returns 1 if the insert is successful
assert (!mem.insert(a_buffer)) else `uvm_warning("APB_SEQ", "Can not insert the desired buffer!");
您可能注意到缓冲区通过set_name()调用获取类型名称。尽管此操作不是必需的,但如果您需要按类型搜索缓冲区,则可能会有所帮助。
一旦停止使用,验证组件应立即释放缓冲区。这可以通过调用缓冲区的deallocate()或地址的deallocate_by_addr()来实现。
// deallocate by buffer
mem.deallocate(a_buffer);
..............................
// deallocate by address
mem.deallocate_by_addr('hCAFE1001);
缓冲区搜索API
一旦缓冲区被验证组件分配,其可以被其他验证组件搜索并用于各种目的(例如,配置,检查,有效载荷检索)。 YAMM提供了一个搜索API,它接受地址,地址范围(或访问)或缓冲区类型作为搜索条件。根据搜索操作,将返回缓冲区或缓冲区列表;如果搜索不成功,则返回空缓冲区或空列表。
// search buffer by address
yamm_buffer a_buffer = mem.get_buffer('hCAFE1001);
..............................
// search buffers by address range or by access
yamm_access basic_access = new;
basic_access.start_addr = 0;
basic_access.size = mem.size/2;
// Get all the buffers contained in the first half of the memory
yamm_buffer queue[$] = mem.get_buffers_by_access(basic_access);
..............................
// search buffers by range
yamm_buffer queue[$] = mem.get_buffers_in_range(0, mem.size/2);
..............................
// search buffers by type
yamm_buffer queue[$] = mem.get_all_buffers_by_type("a_buffer");
缓冲区内容操作
yamm_buffer提供API来处理缓冲区的内容或有效负载(即字节列表)。用户可以覆盖generate_contents()方法来生成特定的缓冲区内容。用户可以通过调用set_contents()来直接设置缓冲区的内容,或者通过调用get_contents()来获取缓冲区的内容。下面的代码框显示了几个使用内容API的示例:
// set buffer's content
a_buffer.set_contents('{‘h54,’h45,’h53,’h54});
...................................
// generate buffer's content
a_buffer.generate_contents();
...................................
// retrieve buffer's content
byte contents[] = a_buffer.get_contents();
...................................
// Compare buffer's contents to a list of bytes
assert (general_buffer.compare_contents(access.payload)) else `uvm_error("APC_SCBD", "Contents is not what I expect!");
如果调用方法get_contents()时未事先初始化缓冲区的内容,则会自动调用generate_contents()方法。
资源
YAMM代码作为 Apache License 2.0下的开源库提供。您可以从GitHub下载 YAMM库。
为了加快速度,您可以下载YAMM的用户手册或浏览HTML文档。