Run HEX File 之 Debug 总集篇

今天就是 Debug 总集篇,
前面都是用猴子自己瞎掰设计的 Code Stream 来验证,
这次终於能够真的执行一个由 gcc 编译出来的程序了!

Debug开发流程

相信大家都还记得昨天提到的 ADDI
观察结构,很明显的是要去存取 stack,
先设定一个记忆体位置让它顺利执行,
之後会尝试用 readelf 从 Binary File 得到资讯来验证

//cpu.cpp
...
       register_file->set_pc(0x1054);
       register_file->set_value_integer(REGISTER_INTERFACE::x2, 0x3FFFFFF);
       while(true) {
                step();
                wait(delay);
        }
...

中间发现有 SW 指令有 Misalignment 的问题,
先假装硬体支援,让它继续执行:

sw address: 3fffffb
Store and AMO Address Misalignment, end simulation!
exception!
current_pc: 0x1058 target_pc: 0x105c SW 2 8 28 rs1Value: 0x3ffffdf rs2Value: 0x0 rdValue: 0x0 immValue: 0x1c

执行之後发现程序不会跟之前一样触发 ILLEGAL_INSTRUCTION_EXCEPTION停下来,
为了观察前面的执行结果,
限制执行的时间 cycle 数:

       int i=0;
       while(true && i<500) {
                step();
                wait(delay);
               i++;
        }

观察 Logger 输出,
发现是 loop 无法结束,会一直无穷回圈:

current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x14a rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x1068 target_pc: 0x106c LW 8 12 15 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x14a immValue: 0xffffffec
current_pc: 0x106c target_pc: 0x1070 ADDI 15 5 15 rs1Value: 0x14f rs2Value: 0x0 rdValue: 0x14f immValue: 0x5
sw address: 3ffffe7
current_pc: 0x1070 target_pc: 0x1074 SW 8 15 8 rs1Value: 0x3ffffff rs2Value: 0x14f rdValue: 0x0 immValue: 0xffffffe8
current_pc: 0x1074 target_pc: 0x1078 LW 8 12 15 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x14a immValue: 0xffffffec
current_pc: 0x1078 target_pc: 0x107c ADDI 15 1 15 rs1Value: 0x14b rs2Value: 0x0 rdValue: 0x14b immValue: 0x1
sw address: 3ffffeb
current_pc: 0x107c target_pc: 0x1080 SW 8 15 12 rs1Value: 0x3ffffff rs2Value: 0x14b rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x1080 target_pc: 0x1084 LW 8 12 14 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x14b immValue: 0xffffffec
current_pc: 0x1084 target_pc: 0x1088 ADDI 0 9 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x9 immValue: 0x9
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x14b rdValue: 0x0 immValue: 0xffffffe0

用 grep 把 BGE 捞出来看

make run | grep BGE

最後发现是 BGE 的 Bug!
从输出可以看到 rs2(0x14a) > rs1(0x9)
但是还是会跳回去 address 0x1068,而不是 address 0x108c

...
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x149 rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x14a rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x14b rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x14c rdValue: 0x0 immValue: 0xffffffe0
...

实际程序

github 页面 Tag: ITDay28

原来是不小心把 rs2 填成 rs1,
修正後就没问题了:

//executor.cpp
...
(register_file->get_value_integer(rs1) >= register_file->get_value_integer(rs2) ?
...

执行结果

可以看到程序在执行到 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x9
然後就跳到下一行,
正常的执行到 JALR 并结束程序。

$make run
...
sw address: 3ffffeb
current_pc: 0x107c target_pc: 0x1080 SW 8 15 12 rs1Value: 0x3ffffff rs2Value: 0x9 rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x1080 target_pc: 0x1084 LW 8 12 14 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x9 immValue: 0xffffffec
current_pc: 0x1084 target_pc: 0x1088 ADDI 0 9 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x9 immValue: 0x9
current_pc: 0x1088 target_pc: 0x1068 BGE 15 14 1 rs1Value: 0x9 rs2Value: 0x9 rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x1068 target_pc: 0x106c LW 8 12 15 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x9 immValue: 0xffffffec
current_pc: 0x106c target_pc: 0x1070 ADDI 15 5 15 rs1Value: 0xe rs2Value: 0x0 rdValue: 0xe immValue: 0x5
sw address: 3ffffe7
current_pc: 0x1070 target_pc: 0x1074 SW 8 15 8 rs1Value: 0x3ffffff rs2Value: 0xe rdValue: 0x0 immValue: 0xffffffe8
current_pc: 0x1074 target_pc: 0x1078 LW 8 12 15 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x9 immValue: 0xffffffec
current_pc: 0x1078 target_pc: 0x107c ADDI 15 1 15 rs1Value: 0xa rs2Value: 0x0 rdValue: 0xa immValue: 0x1
sw address: 3ffffeb
current_pc: 0x107c target_pc: 0x1080 SW 8 15 12 rs1Value: 0x3ffffff rs2Value: 0xa rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x1080 target_pc: 0x1084 LW 8 12 14 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0xa immValue: 0xffffffec
current_pc: 0x1084 target_pc: 0x1088 ADDI 0 9 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x9 immValue: 0x9
current_pc: 0x1088 target_pc: 0x108c BGE 15 14 1 rs1Value: 0x9 rs2Value: 0xa rdValue: 0x0 immValue: 0xffffffe0
current_pc: 0x108c target_pc: 0x1090 ADDI 0 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x1090 target_pc: 0x1094 ADDI 0 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x1094 target_pc: 0x1098 LW 2 28 8 rs1Value: 0x3ffffdf rs2Value: 0x0 rdValue: 0x0 immValue: 0x1c
current_pc: 0x1098 target_pc: 0x109c ADDI 2 0 2 rs1Value: 0x3ffffff rs2Value: 0x0 rdValue: 0x3ffffff immValue: 0x20
current_pc: 0x109c target_pc: 0x0 JALR 1 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
INVALID: Opcode :0
Illegal Instruction, end simulation!
exception!

Info: /OSCI/SystemC: Simulation stopped by user.

小小的结语

呼,到这边为止,
这个 Simulator 算是完成了吧。

虽然有些地方用简化的方式处理,
还跑着不知道从哪里生出来的执行档,
但是 Logger 很有用, Simulator 也正常跑完了。

接下来就是收尾的部分了,
还要交代一下怎麽准备编译环境,
再给这个专案一个范例程序和使用说明。

尝试性的写了 Memory Hierarchy 的文章,
也花了很多时间研究和准备 ONNC、
Branch Predictor、OOO Execution 相关章节,
但还是觉得目前的进度来说不适合放在这个系列文,
不是走马看花,就是花太多时间导致专案目标无法达成,
就留待赛後吧。

这段时间每天都在观察自己的变化,
兴趣广泛是优点也是缺点,
虽然很容易因为时间不够放弃一些东西,
但是当一只每天都对新知识兴致勃勃的猴子也过得蛮快乐的。


<<:  EP 28 - [Ruby on Rails] 付款非同步通知

>>:  Day28-用jQuery写得出ToDoList吗_3_id的重要性与作用

[Day 05] 当我~们同在一起在17在17 (k-means 理论篇)

前言 有一说一,表情辨识到底还是个分类任务。 如果我说有一种演算法可以在不需要标签的情况下自动帮我们...

Day03:浅谈 Git 和 GitHub

Git Git 是一个开源的分布式版本控制系统, 允许我们跟踪档案异动, 最初目的是为更好地管理 L...

Day29_CSS语法12

不知不觉来到了尾声,最後来和大家介绍渐层的属性 linear-gradient(线性渐层) 角度|方...

Day 19: SOLID 设计原则 — LSP (待改进中... )

「在物件导向革命的最初几年,我们将 LSP 视为指导『继承的使用』的一种方式。然而,LSP 可以扩...

从零开始的8-bit迷宫探险【Level 6】Swift 基础语法 (四)

今日目标 认识类别 (class) 及继承 认识协定 (protocol) 认识结构 (struct...