# 5.2寄存器机模拟器

> 译者： [https://sicp.comp.nus.edu.sg/chapters/101](https://sicp.comp.nus.edu.sg/chapters/101)



为了更好地了解套准机的设计，我们必须测试我们设计的机器，看看它们是否按预期运行。 测试设计的一种方法是手动模拟控制器的操作，如练习 [5.5](99#ex_5.5) 所示。 但这对于除最简单的机器以外的所有机器都非常繁琐。 在本节中，我们为用注册机器语言描述的机器构造一个模拟器。 模拟器是具有四个接口功能的源程序。 第一个使用注册机器的描述来构建机器模型（数据结构的部分与要模拟的机器的部分相对应的数据结构），而其他三个模型则允许我们通过操纵模型来模拟机器：

*   `make_machine(` ![%5Ctextit%7Bregister-names%7D%5Ctexttt%7B%2C%7D](img/0aa214b116ff336dae68a0b30677745d.jpg) ![%5Ctextit%7Boperations%7D%5Ctexttt%7B%2C%7D](img/de79a7fed52aeaba76aeba44e6af5bae.jpg) ![%5Ctextit%7Bcontroller%7D](img/456e2c93cf7dc246540f7096a7b80916.jpg) `);`
    构造并返回具有给定寄存器，操作和控制器的机器模型。
*   `set_register_contents(` ![%5Ctextit%7Bmachine-model%7D%5Ctexttt%7B%2C%7D](img/06e428e0f380ae068a33c4e1dec05706.jpg) ![%5Ctextit%7Bregister-name%7D%5Ctexttt%7B%2C%7D](img/143d41067131cd212d22341c58043efb.jpg) ![%5Ctextit%7Bvalue%7D](img/8941e10ab9faad8a97352258c597168e.jpg) `);`
    将值存储在给定机器的模拟寄存器中。
*   `get_register_contents(` ![%5Ctextit%7Bmachine-model%7D%5Ctexttt%7B%2C%7D](img/06e428e0f380ae068a33c4e1dec05706.jpg) ![%5Ctextit%7Bregister-name%7D](img/c2d0b9b093f6a7aa4d32b06f88b8b756.jpg) `);`
    返回给定机器中模拟寄存器的内容。
*   `start(` ![%5Ctextit%7Bmachine-model%7D](img/10fac89f48ea44daac0ce3d5786e2367.jpg) `);`
    模拟给定机器的执行，从控制器序列的开头开始，直到控制器序列的末尾停止。

作为如何使用这些功能的示例，我们可以将`gcd_machine()`定义为 [5.1.1](96) 部分的GCD机器的模型：

```js
function gcd_machine() {
    return make_machine(list("a", "b", "t"),
                        list(list("rem", binary_function((a, b) => a % b)),
                             list("=", binary_function((a, b) => a === b))),
                        list("test-b",
                             test(op("="), reg("b"), constant(0)),
                             branch(label("gcd-done")),
                             assign("t", list(op("rem"), reg("a"), reg("b"))),
                             assign("a", list(reg("b"))),
                             assign("b", list(reg("t"))),
                             go_to(label("test-b")),
                             "gcd-done"));
}
```

The first argument to `make_machine` is a list of register names. The next argument is a table (a list of two-element lists) that pairs each operation name with a Scheme function that implements the operation (that is, produces the same output value given the same input values). The last argument specifies the controller as a list of labels and machine instructions, as in section <ref name="sec:designing-register-machines">[5.1](95)</ref>.

为了在此机器上计算GCD，我们设置输入寄存器，启动机器，并在模拟终止时检查结果：

```js
set_register_contents(gcd_machine, "a", 206); 
"done"
```

```js
set_register_contents(gcd_machine, "b", 40);
"done"
```

```js
start(gcd_machine);
"done"
```

```js
get_register_contents(gcd_machine, "a");
2
```

这种计算的运行速度比Scheme中编写的gcd函数要慢得多，因为我们将通过更复杂的操作来模拟低级机器指令，例如Assign。

<exercise>Use the simulator to test the machines you designed in exercise <ref name="ex:design-reg-machines">[5.4](99#ex_5.4)</ref>.<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#no_solution_101_1_div">Add solution</button>There is currently no solution available for this exercise. This textbook adaptation is a community effort. Do consider contributing by providing a solution for this exercise, using a Pull Request in [Github](https://github.com/source-academy/sicp).</exercise>