5.1.1 描述寄存器机器的语言

 5.1.1 描述寄存器机器的语言
数据路径图和控制器图对于表示像求最大公约数这样的简单机器是足够的了。
但是用它们来描述如LISP解释器这样的大型机器就是不明智的了。为了能够实现复杂的机器,
我们创建一个语言以文本的格式,来表示被数据路径与控制器提供的信息。
我们将开始一种标记法来直接对数据路径图与控制器图进行表示。

通过描述寄存器和操作我们定义一个机器的数据路径。为了描述寄存器,我们能给它一个名称,
指定一个按钮来控制对它的赋值。我们给这些按钮的任何一个起名称,并且指定在按钮的控制下,
进行寄存器的数据的来源。(来源包括一个寄存器或者是常数,或者是一个操作)。为了描述一
个操作,我们给它一个名称,指定它的输入(寄存器或者是常数)

我们定义一个机器的控制器作为指令的序列加上标签,标签标识着在序列中的入口处。
一个指令是如下的内容的一种。

             .为了赋值给一个寄存器的按钮的名称( 这对应于控制器图中的一个盒子)
             .一个测试指令,它执行指定的测试
             .一个条件的分支(分支指令)它的位置被一个控制器标签指定,基于前面的测试结果
(在控制器图中,测试加上分支一起对应于方块)如果测试为假,控制器应该继续序列中的下面的指令。
否则,控制器应该继续标签后面的指令。
            .一个非条件的分支(goto 指令)命名了一个标签,直接执行这个标签处的指令。

机器在控制器的指令序列的开始处启动,并且在当它到达序列的结尾处时停止。除了一个分支改变了控制流,指令被执行按照它们被列出的顺序。

(data-paths 
         (registers 
                ((name  a)  (buttons  ((name  a<-b)  (source  (register  b))))) 
                ((name  b)  (buttons  ((name  b<-t)   (source (register   t)))))
                ((name   t)  (buttons  ((name  t<-r)    (source (register  rem)))))) 
         (operations 
                ((name rem)  (inputs  (register  a)  (register  b))) 
                ((name  =)     (register  b) (constant  0)))))

(controller 
         test-b 
               (test  =) 
               (branch  (label  gcd-done))
               (t<-r)       
               (a<-b)
               (b<-t)
               (goto (label  test-b))
        gcd-done
)

图5.3  一个GCD机器的规范

图5.3显示了以这种方式描述的GCD机器。这个例子仅提示了
这种描述的通用性,因为GCD机器是一个十分简单的例子:每个
寄存器只有一个按钮,每个按钮和测试在控制器中仅使用一次。

不幸的是,阅读这样的描述是很困难的。为了理解控制器的指令,我们必须
马上回到按钮名称和操作名称的定义处,为了理解按钮做什么事,我们可能必须
引用操作名称的定义。我们将因此转换我们的观念,来把我们已经看到的数据路径
和控制器的描述的信息组合起来。

为了得到这个形式的描述,我们将用按钮和操作的名称的行为来替换按钮和操作的名称。
也就是,代替了控制器图中说的“按钮 t<-r”和单独在数据路径图中说“按钮 t<-r
把rem操作的值赋给寄存器t”和 “rem操作的输入内容是寄存器a和 b的内容”
我们将在控制器图中说“按下按钮,把rem操作的寄存器a,b的内容的值赋给寄存器t”
相似的,代替说在控制器图中,“执行相等测试”和单独地在数据路径图中说
“相等测试操作的是b的值和常数0” 我们将忽略了数据路径图的描述,仅留下控制器的序列。
因此,GCD机器的描述如下:

(controller 
         test-b 
               (test  (op =) (reg b) (const 0)) 
               (branch  (label  gcd-done))
               (assign  t  (op rem)  (reg  a) (reg b))       
               (assign  a  (reg b))
               (assign  b  (reg t))
               (goto (label  test-b))
        gcd-done
)

这种形式的描述是比图5.3中显示的那种形式更容易阅读的,但是也有它的缺点:

.对于大型的机器 ,这有太详细的细节了,因为在控制器图中指令序列中
只要元素被提到,数据路径图的元素的完整描述就被重复了。(在GCD机器的例子中,
这不是一个问题,因为每个操作和按钮都只用到了一次)进而,重复的数据路径的描述妨碍了
机器的实际的数据路径的结构,对于大型机器而言,有多少寄存器,操作,按钮并且它们是
如何相互的,这些情况都是不明显的。

.在一个机器定义中的控制器指令看起来像Lisp表达式,很容易忘记它们不是普通的Lisp表达式。
它们仅能标记合法的机器操作。例如,操作仅能直接操作常数和寄存器的内容,而不是其它操作的结果。

尽管这些不足,我们将在本章中使用这个寄存器-机器语言,因为我们将更加关注的是理解
控制器而不是理解数据路径的元素与连接。我们应该记住,然而,在设计真实的机器时,
数据路径的设计是关键的。

练习5.2 
使用这个寄存器-机器语言来描述练习5.1中的迭代的斐波那些数的机器。

*动作
让我们修改GCD机器,让我们能够向我们要的GCD中输入数据,并且在我们的终端上
得到答案。我们没有讨论如何让一个机器能够读取和打印,但是将假定它们作为
原生的操作是可用的。(这正像我们在scheme中使用read,display时我们所做的那样)

读取像我们已经使用了的操作,它生成一个值被存储在一个寄存器中。但是读取没有从任何
寄存器中得到输入,它的值依赖我们设计好的机器的部分的外部发生的情况。我们将允许我们的
机器的操作有这样的行为,并且因此将画出与标识出读取的使用,正如我们为了计算一个值
所做的其它的操作。

打印,另一个方面,它不同于以基础的方式,我们已经使用的操作,它没有生成一个存储在
寄存器中的输出值。尽管这有一个效应,这个效应也不是我们设计的机器的一部分。
我们将把这种操作叫做动作。在一个数据路径图中,我们表示一个动作,正如我们表示一个计算
一个值的操作,作一个 包括它的名称。从任何的输入(寄存器或者是常数)用箭头指向动作的盒子。
按下按钮,让动作发生。为了让一个控制器按下一个动作的按钮,我们使用一种新型的指令叫做执行。
因此,打印寄存器a的值的动作是表示在控制器图中的一个指令

(perform  (op print)  (reg a))

图5.4显示了新的GCD机器的数据路径和控制器。代替了打印了结果之后机器停止,我们让它重开始,为了
能够重复读取另一个数据对,计算它们的GCD,并且打印结果。这个结构类似于在第四章中的解释器的驱动
循环。

(controller 
   gcd-loop
     (assign  a (op read))
     (assign  b (op read))
          test-b 
               (test  (op =) (reg b) (const 0)) 
               (branch  (label  gcd-done))
               (assign  t  (op rem)  (reg  a) (reg b))       
               (assign  a  (reg b))
               (assign  b  (reg t))
               (goto (label  test-b))
        gcd-done
              (perform  (op print)  (reg a))
              (goto (label  gcd-loop))
)

图5.4  读取输入和打印输出的一个GCD机器

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/83040796