第1章 验证导论 1
1.1验证流程 2
1.1.1不同层次上的测试 2
1.1.2验证计划 3
1.2验证方法学 3
1.3基本测试平台的功能 4
1.4定向测试 4
1.5方法学基础 5
1.6受约束的随机激励 6
1.7你的随机化对象是什么 7
1.7.1设备和环境配置 7
1.7.2输入数据 8
1.7.3协议异常、错误和违例 8
1.7.4时延和同步 9
1.7.5并行的随机测试 9
1.8功能覆盖率 9
1.8.1从功能覆盖率到激励的反馈 10
1.9测试平台的构件 11
1.10分层的测试平台 11
1.10.1不分层的测试平台 12
1.10.2信号和命令层 13
1.10.3功能层 14
1.10.4场景层 14
1.10.5测试的层次和功能覆盖率 15
1.11建立一个分层的测试平台 16
1.11.1创建一个简单的驱动器 16
1.12仿真环境的阶段 16
1.13最大限度的代码重用 17
1.14测试平台的性能 17
1.15结束语 18
第2章数据类型 19
2.1内建数据类型 19
2.1.1逻辑(logic)类型 19
2.1.2双状态数据类型 20
2.2定宽数组 21
2.2.1定宽数组的声明和初始化 21
2.2.2常量数组 22
2.2.3基本的数组操作——for和foreach 22
2.2.4基本的数组操作——复制和比较 24
2.2.5同时使用位下标和数组下标 25
2.2.6合并数组 25
2.2.7合并数组的例子 26
2.2.8合并数组和非合并数组的选择 27
2.3动态数组 27
2.4队列 28
2.5关联数组 30
2.6链表 32
2.7数组的方法 32
2.7.1数组缩减方法 33
2.7.2数组定位方法 34
2.7.3数组的排序 36
2.7.4使用数组定位方法建立记分板 36
2.8选择存储类型 37
2.8.1灵活性 37
2.8.2存储器用量 37
2.8.3速度 38
2.8.4排序 38
2.8.5选择最优的数据结构 39
2.9使用typedef创建新的类型 39
2.10创建用户自定义结构 40
2.10.1使用struct创建新类型 41
2.10.2对结构进行初始化 41
2.10.3创建可容纳不同类型的联合 41
2.10.4合并结构 42
2.10.5在合并结构和非合并结构之间进行选择 42
2.11类型转换 42
2.11.1静态转换 43
2.11.2动态转换 43
2.11.3流操作符 43
2.12枚举类型 45
2.12.1定义枚举值 46
2.12.2枚举类型的子程序 46
2.12.3枚举类型的转换 47
2.13 常量 48
2.14字符串 48
2.15表达式的位宽 49
2.16结束语 50
第3章 过程语句和子程序 51
3.1过程语句 51
3.2任务、函数以及void函数 52
3.3任务和函数概述 53
3.3.1在子程序中去掉begin…end 53
3.4子程序参数 53
3.4.1 C语言风格的子程序参数 53
3.4.2参数的方向 54
3.4.3高级的参数类型 54
3.4.4参数的缺省值 56
3.4.5采用名字进行参数传递 57
3.4.6常见的代码错误 57
3.5子程序的返回 58
3.5.1返回(return)语句 58
3.5.2从函数中返回一个数组 59
3.6局部数据存储 60
3.6.1自动存储 60
3.6.2变量的初始化 60
3.7时间值 61
3.7.1时间单位和精度 61
3.7.2时间参数 62
3.7.3时间和变量 62
3.7.4 $time与$realtime的对比 63
3.8结束语 63
第4章 连接设计和测试平台 65
4.1将测试平台和设计分开 65
4.1.1测试平台和DUT之间的通信 66
4.1.2与端口的通信 66
4.2接口 68
4.2.1使用接口来简化连接 68
4.2.2连接接口和端口 70
4.2.3使用modport将接口中的信号分组 70
4.2.4在总线设计中使用modport 71
4.2.5创建接口监视模块 71
4.2.6接口的优缺点 72
4.2.7更多例子和信息 73
4.3激励时序 73
4.3.1使用时钟块控制同步信号的时序 73
4.3.2接口中的logic和wire对比 74
4.3.3 Verilog的时序问题 75
4.3.4测试平台一设计间的竞争状态 76
4.4.4程序块(Program Block)和时序区域(Timing Region) 76
4.3.6仿真的结束 78
4.3.7指定设计和测试平台之间的延时 78
4.4接口的驱动和采样 79
4.4.1接口同步 79
4.4.2接口信号采样 79
4.4.3接口信号驱动 80
4.4.4通过时钟块驱动接口信号 81
4.4.5接口中的双向信号 82
4.4.6为什么在程序(program)中不允许使用always块 83
4.4.7时钟发生器 83
4.5将这些模块都连接起来 84
4.5.1端口列表中的接口必须连接 85
4.6顶层作用域 85
4.7程序——模块交互 87
4.8 SystemVerilog断言 88
4.8.1立即断言(Immediate Assertion) 88
4.8.2定制断言行为 88
4.8.3并发断言 89
4.8.4断言的进一步探讨 90
4.9四端口的ATM路由器 90
4.9.1使用端口的ATM路由器 90
4.9.2使用端口的ATM顶层网单 91
4.9.3使用接口简化连接 94
4.9.4 ATM接口 94
4.9.5使用接口的ATM路由器模型 95
4.9.6使用接口的ATM顶层网单 95
4.9.7使用接口的ATM测试平台 96
4.10 ref端口的方向 97
4.11仿真的结束 97
4.12 LC3取指模块的定向测试(directed test) 97
4.13结论 102
第5章 面向对象编程基础 103
5.1概述 103
5.2考虑名词,而非动词 103
5.3编写第一个类(Class) 104
5.4在哪里定义类 105
5.5 OOP术语 105
5.6创建新对象 106
5.6.1没有消息就是好消息 106
5.6.2定制构造函数(Constructor) 106
5.6.3将声明和创建分开 108
5.6.4 new和new[]的区别 108
5.6.5为对象创建一个句柄 108
5.7对象的解除分配(deallocation) 109
5.8使用对象 110
5.9静态变量和全局变量 111
5.9.1简单的静态变量 111
5.9.2通过类名访问静态变量 112
5.9.3静态变量的初始化 112
5.9.4静态方法 112
5.10类的方法 114
5.11在类之外定义方法 115
5.12作用域规则 116
5.12.1 this是什么 118
5.13在一个类内使用另一个类 119
5.13.1我的类该做成多大 120
5.13.2编译顺序的问题 121
5.14理解动态对象 121
5.14.1将对象传递给方法 121
5.14.2在任务中修改句柄 123
5.14.3在程序中修改对象 123
5.14.4句柄数组 124
5.15对象的复制 125
5.15.1使用new操作符复制一个对象 125
5.15.2编写自己的简单复制函数 126
5.15.3编写自己的深层复制函数 127
5.15.4使用流操作符从数组到打包对象,或者从打包对象到数组 128
5.16公有和私有 130
5.17题外话 130
5.18建立一个测试平台 131
5.19结论 132
第6章 随机化 133
6.1介绍 133
6.2什么需要随机化 133
6.2.1器件配置 134
6.2.2环境配置 134
6.2.3原始输入数据 135
6.2.4封装后的输入数据 135
6.2.5协议异常、错误(error)和违规(violation) 135
6.2.6延时 135
6.3 SystemVerilog中的随机化 135
6.3.1带有随机变量的简单类 136
6.3.2检查随机化(randomize)的结果 137
6.3.3约束求解 137
6.3.4什么可以被随机化 137
6.4约束 137
6.4.1什么是约束 138
6.4.2简单表达式 139
6.4.3等效表达式 139
6.4.4权重分布 140
6.4.5集合(set)成员和inside运算符 141
6.4.6在集合里使用数组 142
6.4.7条件约束 145
6.4.8双向约束 145
6.4.9使用合适的数学运算来提高效率 146
6.5解的概率 147
6.5.1没有约束的类 147
6.5.2关系操作 147
6.5.3关系操作和双向约束 148
6.5.4使用solve…before约束引导概率分布 148
6.6控制多个约束块 149
6.7有效性约束 150
6.8内嵌约束 151
6.9 pre-randomize和post-randomize函数 152
6.9.1构造浴缸型分布 152
6.9.2关于void函数 153
6.10随机数函数 153
6.11约束的技巧和技术 154
6.11.1使用变量的约束 154
6.11.2使用非随机值 155
6.11.3用约束检查值的有效性 156
6.11.4随机化个别变量 156
6.11.5打开或关闭约束 156
6.11.6在测试过程中使用内嵌约束 158
6.11.7在测试过程中使用外部约束 158
6.11.8扩展类 159
6.12随机化的常见错误 159
6.12.1小心使用有符号变量 159
6.12.2提高求解器性能的技巧 160
6.13迭代和数组约束 160
6.13.1数组的大小 160
6.13.2元素的和 161
6.13.3数组约束的问题 162
6.13.4约束数组和队列的每一个元素 164
6.13.5产生具有唯一元素值的数组 165
6.13.6随机化句柄数组 168
6.14产生原子激励和场景 168
6.14.1和历史相关的原子发生器 169
6.14.2随机序列 169
6.14.3随机对象数组 170
6.14.4组合序列 170
6.15随机控制 170
6.15.1用randcase建立决策树 171
6.16随机数发生器 172
6.16.1伪随机数发生器 172
6.16.2随机稳定性——多个随机发生器 173
6.16.3随机稳定性和层次化种子 174
6.17随机器件配置 175
6.18结论 178
第7章 线程以及线程间的通信 179
7.1线程的使用 180
7.1.1使用fork…join和begin…end 180
7.1.2使用fork…join-none来产生线程 181
7.1.3使用fork…join-any实现线程同步 182
7.1.4在类中创建线程 183
7.1.5动态线程 184
7.1.6线程中的自动变量 185
7.1.7等待所有衍生线程 187
7.1.8在线程间共享变量 188
7.2停止线程 189
7.2.1停止单个线程 189
7.2.2停止多个线程 190
7.2.3禁止被多次调用的任务 191
7.3线程间的通信 192
7.4事件 192
7.4.1在事件的边沿阻塞 192
7.4.2等待事件的触发 193
7.4.3在循环中使用事件 194
7.4.4传递事件 195
7.4.5等待多个事件 195
7.5旗语 197
7.5.1旗语的操作 198
7.5.2带多个钥匙的旗语 199
7.6信箱 199
7.6.1测试平台里的信箱 201
7.6.2定容信箱 203
7.6.3在异步线程间使用信箱通信 204
7.6.4使用定容信箱和探视(peek)来实现线程的同步 206
7.6.5使用信箱和事件来实现线程的同步 207
7.6.6使用两个信箱来实现线程的同步 209
7.6.7其他的同步技术 211
7.7构筑带线程并可实现线程间通信的测试程序 211
7.7.1基本的事务处理器 211
7.7.2配置类 212
7.7.3环境类 212
7.7.4测试程序 214
7.8结束语 214
第8章 面向对象编程的高级技巧指南 215
8.1继承简介 215
8.1.1事务基类 216
8.1.2 Transaction类的扩展 217
8.1.3更多的OOP术语 218
8.1.4扩展类的构造函数 218
8.1.5驱动类 218
8.1.6简单的发生器类 219
8.2蓝图(Blueprint)模式 220
8.2.1 environment类 222
8.2.2一个简单的测试平台 222
8.2.3使用扩展的Transaction类 223
8.2.4使用扩展类改变随机约束 224
8.3类型向下转换(downcasting)和虚方法 224
8.3.1使用$cast作类型向下转换 224
8.3.2虚方法 226
8.3.3签名 228
8.4合成、继承和其他替代的方法 228
8.4.1在合成和继承之间取舍 228
8.4.2合成的问题 229
8.4.3继承的问题 230
8.4.4现实世界中的其他方法 231
8.5对象的复制 232
8.5.1 copy-data方法 232
8.5.2指定复制的目标 234
8.6抽象类和纯虚方法 235
8.7回调 237
8.7.1创建一个回调任务 237
8.7.2使用回调来注入干扰 238
8.7.3记分板简介 239
8.7.4与使用回调的记分板进行连接 240
8.7.5使用回调来调试事务处理器 241
8.8参数化的类 242
8.8.1一个简单的堆栈(stack) 242
8.8.2关于参数化类的建议 244
8.9结论 245
第9章 功能覆盖率 246
9.1覆盖率的类型 249
9.1.1代码覆盖率 249
9.1.2功能覆盖率 250
9.1.3漏洞率 250
9.1.4断言覆盖率 251
9.2功能覆盖策略 251
9.2.1收集信息而非数据 251
9.2.2只测量你将会使用到的内容 252
9.2.3测量的完备性 252
9.3功能覆盖率的简单例子 253
9.4覆盖组详解 256
9.4.1在类里定义覆盖组 256
9.5覆盖组的触发 257
9.5.1使用回调函数进行采样 257
9.5.2使用事件触发的覆盖组 258
9.5.3使用SystemVerilog断言进行触发 259
9.6数据采样 259
9.6.1个体仓和总体覆盖率 260
9.6.2自动创建仓 260
9.6.3限制自动创建仓的数目 260
9.6.4对表达式进行采样 261
9.6.5使用用户自定义的仓发现漏洞 262
9.6.6命名覆盖点的仓 263
9.6.7条件覆盖率 264
9.6.8为枚举类型创建仓 265
9.6.9翻转覆盖率 266
9.6.10在状态和翻转中使用通配符 266
9.6.11忽略数值 266
9.6.12不合法的仓 267
9.6.13状态机的覆盖率 268
9.7交叉覆盖率 268
9.7.1基本的交叉覆盖率的例子 268
9.7.2对交叉覆盖仓进行标号 269
9.7.3排除掉部分交叉覆盖仓 271
9.7.4从总体覆盖率的度量中排除掉部分覆盖点 271
9.7.5从多个值域中合并数据 272
9.7.6交叉覆盖的替代方式 272
9.8通用的覆盖组 274
9.8.1通过数值传递覆盖组参数 274
9.8.2通过引用传递覆盖组参数 274
9.9覆盖选项 275
9.9.1单个实例的覆盖率 275
9.9.2覆盖组的注释 276
9.9.3覆盖阈值 276
9.9.4打印空仓 276
9.9.5覆盖率目标 277
9.10覆盖率数据的分析 277
9.11在仿真过程中进行覆盖率统计 278
9.12结束语 279
第10章 高级接口 281
10.1 ATM路由器的虚接口 281
10.1.1只含有物理接口的测试平台 281
10.1.2使用虚接口的测试平台 284
10.1.3将测试平台连接到端口列表中的接口 287
10.1.4使用XMR(跨模块引用)连接接口和测试程序 288
10.2连接到多个不同的设计配置 290
10.2.1网格(Mesh)设计案例 290
10.2.2对虚接口使用typedef 293
10.2.3使用端口传递虚接口数组 294
10.3接口中的过程代码 295
10.3.1并行协议接口 295
10.3.2串行协议接口 296
10.3.3接口代码的局限性 298
10.4结论 298
第11章 完整的SystemVerilog测试平台 299
11.1设计单元 299
11.2测试平台的模块 303
11.3修改测试 326
11.3.1第一个测试——只有一个信元的测试 326
11.3.2随机丢弃信元 327
11.4结论 328
第12章SystemVerilog与C语言的接口 329
12.1传递简单的数值 329
12.1.1传递整数和实数类型 329
12.1.2导入(import)声明 330
12.1.3参数方向 331
12.1.4参数类型 331
12.1.5导入数学库函数 332
12.2连接简单的C子程序 333
12.2.1使用静态变量的计数器 333
12.2.2 chandle数据类型 334
12.2.3值的压缩(packed) 336
12.2.4四状态数值 337
12.2.5从双状态数值转换到四状态数值 339
12.3调用C+++程序 339
12.3.1C+++中的计数器 339
12.3.2静态方法 340
12.3.3和事务级(Transaction Level)C+++模型通信 341
12.4共享简单数组 344
12.4.1一维数组——双状态 344
12.4.2一维数组——四状态 345
12.5开放数组(open array) 346
12.5.1基本的开放数组 346
12.5.2开放数组的方法 347
12.5.3传递大小未定义的开放数组 348
12.5.4 DPI中压缩(packed)的开放数组 349
12.6共享复合类型 349
12.6.1在SystemVerilog和C之间传递结构 350
12.6.2在SystemVerilog和C之间传递字符串 351
12.7纯导入方法和关联导入方法 352
12.8在C中与SystemVerilog通信 353
12.8.1一个简单的导出方法 353
12.8.2调用SystemVerilog函数的C函数 354
12.8.3调用SystemVerilog任务的C任务 355
12.8.4调用对象中的方法 357
12.8.5上下文(context)的含义 360
12.8.6设置导入函数的作用域 361
12.9与其他语言交互 363
12.10结论 364