<symbol> ::= __expression1__
, 其中__expression1__
可以为<sel1>|<sel2>
这样NEMU and RTL design: 在
src/isa/$ISA/inst.c
中看如何一一对应
IFU =inst_fetch(&s->snpc,4)
取指
IDU =decode_exec(s)
解码
EXU = also indecode_exec(s)
, e.g.R(rd) = s->pc + imm
whereR(i) = gpr(i)
执行,读取与写入寄存器和内存
更新PC
Runtime Error: 如果返回值非 0 则表示命令执行出现错误。因此在命令正常退出 (如收到 q 命令后) 应当返回 0。一个不合适的方法是直接 exit 退出。合适的方式是正确地设置 nemu_state——直接退出可能导致部分逻辑未被执行。
NEMU初始化后调用engine_start
in src/engine/interpreter/init.c
, 退出于is_status_exit_bad
in src/utils/state.c
. 退出值描述: 正确的退出 = (NEMU_STOP)程序完成 | (NEMU_QUIT)cmd_q退出.
退出的错误是因为: cmd_q没有修改state直接返回(-1),使程序强制退出于错误的状态.
命令 | 格式 | 使用举例 | 说明 |
---|---|---|---|
帮助(1) | help | help | 打印命令的帮助信息 |
继续运行(1) | c | c | 继续运行被暂停的程序 |
退出(1) | q | q | 退出NEMU |
单步执行 | si [N] | si 10 | 让程序单步执行 N 条指令后暂停执行,当 N 没有给出时,缺省为 1 |
打印程序状态 | info SUBCMD | info r | 打印寄存器状态 |
info w | 打印监视点信息 | ||
扫描内存(2) | x N EXPR | x 10 $esp | 求出表达式 EXPR 的值,将结果作为起始内存地址,以十六进制形式输出连续 N 个4字节 |
表达式求值 | p EXPR | p $eax + 1 | 求出表达式 EXPR 的值,EXPR 支持的运算请见调试中的表达式求值小节 |
设置监视点 | w EXPR | w *0x2000 | 当表达式 EXPR 的值发生变化时,暂停程序执行 |
删除监视点 | d N | d 2 | 删除序号为 N 的监视点 |
exec_once(&s,cpu.pc)
in execute(-1)
void isa_reg_display(void);
形如/定位符 (匹配的字符) 定位符或限定符/修饰符
. 包括了
普通字符: a-z
0-9
.
=[^\n\r]
\w
=[A-Za-z0-9_]
\d
=[0-9]
非打印字符: 换行符\n
制表符\t
任何空白字符\s
任何非空白字符\S
限定符:
限定符 | 功能 |
---|---|
* |
匹配前面的子表达式>=0次 |
+ |
匹配前面的子表达式>=1次 |
? |
匹配前面的子表达式0/1次 |
{n} |
匹配前面的子表达式n次 |
{n,} |
匹配前面的子表达式至少n次 |
{n,m} |
匹配前面的子表达式[n,m]次 |
*
和 +
会尽可能多的匹配文字,在它们的后面加上一个 ?
可以实现最小匹配
定位符: 字符串开始^
字符串结束$
单词前/后边界\b
非单词边界\B
限定符与定位符不能一起使用
选择: 用()
表示捕获分组,用 |
分隔相邻的选择项,相关匹配被存到缓存区
例如,
var str = "https://www.runoob.com:80/html/html-tutorial.html";
var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/;
arr = str.match(patt1);
for (var i = 0; i < arr.length ; i++) {
document.write(arr[i]);
document.write("<br>");
}
分别得到https, www.runoob.com, :80, /html/html-tutorial.htm
修饰符: 位于表达式之外,形如/pattern/flags
修饰符 | 功能 |
---|---|
i |
ignore 大小写 |
g |
global 全局 |
m |
multi-line ^ $ 匹配每一行(而非字符串)的开头和结尾 |
s |
. 包含 \n |
特殊字符需要转义
预先编译规则: init_regex()
int regcomp (regex_t *preg, const char *regex, int cflags)
compile a regular expression into a form for regexec()
to search. preg
pointer to a pattern buffer storage area; regex
pointer to string?; cflags
type of compilation
识别token: make_token()
int regexec (const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
match string
against precompiled pattern buffer preg
如果regexec识别到, 就存入tokens[wpr]结构体中
运算符存储type, 数字存储str和type
如果修改结构体中的str为int是不是更好?在读入时就识别数字和括号的深度存入
特殊处理: 如果读入的token放不下怎么办?return -1;
divide and conquer 分治法: 长表达式 = 递归(短表达式)
eval() + check_parentheses()
括号匹配:
- 预先用Stack处理,记录括号编号于结构体中
- Balanced Substring Checks (缺点:每次都要遍历)
- Segment Tree or Binary Indexed Tree
注意同级运算符的顺序: 从右至左
- 为什么要使用无符号类型? (建议二周目思考) 我们在表达式求值中约定, 所有运算都是无符号运算. 你知道为什么要这样约定吗? 如果进行有符号运算, 有可能会发生什么问题?
表达式求值递归的每一次计算都是无符号运算; 应该把测试样例生成的数至少一部分设成unsigned类型, 否则测试样例只有最终一次求值是无符号数: 例如, 正确的结果为16/(-8) = 16/(2^32-8) = 0, 错误的结果为16/(-8) = -2 = 2^32-2;- division by zero?
除零会有warning; 在运行生成的程序时加入-Wall -Werror
将warning转为error,程序运行出现error后退出不会输出这一行
长表达式结果不对?
分割测试(实际上也不会出现这么长的)
break point: program specific, stop on a specific statement (function, line, value)
b main
b 2
b 8 if i==500
watch point: field specific, stop when the triggering variable is accessed
awatch var
awatch
for read/write, rwatch
for read, watch
for write
info breakpoints
shows both breakpoints and watchpoints
池是什么?事先创建对象保存在列表中,即取即用,用完归还,最后统一释放
监视点池存储所有监视点,链表分别接上used和free的监视点结构
需要完成的内容:
WP* new_wp
void free_wp(WP* wp)
即singly linked listcmd_w
in sdb.c 读取表达式等内容写入new_wp()
取用的WP结构体trace_and_difftest
in cpu_exec.c扫描head链表,求值;如果值变化, state=NEMU_STOPinfo_w
打印head链表d NO
遍历head找到NO对应的WP, 调用free_wp(WP* wp)