Skip to content
计算机组成原理:编程与调试
📆2022-03-15 | ✍2022-03-16 | 📂计算机架构

结构化编程

它起源于20世纪50年代,Edsger W. Dijkstra在1968年正式确立此概念。结构化编程改进了“过程式编程”,它主张使用系统分解的方法解决问题。

系统分解

一个任务视为一个工作单元。本方法将任务分解成多个子工作单元,而它们的集合功能与父工作单元一致。

任务分解后,子任务仍然过于复杂,那么继续分解,直到小模块可用程序描叙。此乃逐步求精

基础结构

任务的分解遵照以下逻辑:

  • 顺序:将任务分解成两个有序的子任务。
  • 条件:将任务分解成两个时序互斥的子任务,执行何者视条件而定。
  • 迭代:循环执行子任务。

它们都是二元操作,因此多元化与嵌套是合理的。

任务的入口与出口分别只有一个。

用LC-3构造基础逻辑

顺序

顺序指令框图

非常简单,执行指令绝不回头。

条件

条件指令框图

针对某项操作,在BR之前执行其指令,留下条件码。B2处为条件指令。若条件满足,则PC偏移到C2 + 1;否则,PC不变,.即将执行与Subtask 1时序互斥的Subtask 2。C2处为无条件分支,直接令PC偏移到D2 + 1,终结整个逻辑。

迭代

迭代指令框图

先留下条件码,让B3处的条件指令核对。若条件满足,则PC偏移到D3 + 1,终结整个逻辑;否则,PC不变,即将执行循环体。D3处为无条件分支,负责拉PC回到循环条件处。

编程心得

刚接手一段代码就想彻底搞懂,多数时候并不可能。

你可以试着截取一部分代码,从此开始探索。

问题起初是模糊的,随着分析愈加明朗。一旦你弄明白任务所需、所供,以及如何展开,就可以去系统分解其它任务了。

调试

软件开发过程中,调试往往比设计和施工花更长时间。

当程序出现逻辑谬误时,可通过回溯追踪它。跟随指令执行流,比较实际结果与应然结果,即可识别出逻辑谬误所在。

回溯调试

回溯调试的模拟器必须具备以下功能:

  • 写入某些值到内存和寄存器
  • 执行一系列指令
  • 指定情况下暂停执行
  • 观察内存和寄存器内的值

设定值

截取一部分代码进行调试,须消除先前代码的影响。因此,应该假设正确用例,保证调试环境正常。

实践中,是将值写入待用的寄存器。

执行流

模拟器必须拥有以下控制执行流的命令:

  • Run:执行程序,遇到HALT指令或断点才停下。
  • Step:步进,一次执行定量指令。默认一次一条,即所谓的单步。
  • Set Breakpoint:模拟器维护着一份断点地址列表。在指令的FETCH阶段,模拟器会用PC的值查表,若查找命中,则停止执行流。
  • Clear Breakpoint:清除某处断点。

显示值

执行中止就是观察内存或寄存器的时机。

边界情况

对于合乎逻辑的输入集合,若程序只能正确处理一部分,则剩余部分称为边界情况。修复边界情况bug,是调试中最难的问题。

任其崩溃

理想的调试:首次遇到bug诱因,bug便浮现。

良好的设计,应该能在漏洞潜伏的情况下,让bug尽早出现,且声势要大,比如直接崩溃

Last updated: