提出(1993)

2021-04-23 16:58:18

四个社区中的每个人都谈到港口的容易程度 到一个新的CPU。但像许多" Easy"和#34;显而易见的"任务, 没有太多写的是如何做到!所以,当比尔凯贝尔建议这一点时 一篇文章的主题,我决定突破大口头传统 怎样,并记录黑白的过程。

在这些文章的过程中,我将培养6809, 8051和Z80。我在做6809的情况下,我'迈将简单而传统 模型;加上,我已经发表了一台6809档次[rod91,rod92], 和我' ll需要一个6809才能为未来的TCJ项目。我在做的 8051年为大学项目,但它也是一些相当的说明 不同的设计决策。 Z80是针对所有CP / M读者 TCJ,以及一些有关TRS-80S收集灰尘的朋友。

您必须选择CPU。我不会深入研究一个 CPU超过另一个,因为CPU选择通常被迫在你身上 通过其他考虑。此外,本文的对象是展示 如何向任何CPU申请。

您可以期待通常的16位新内核(见下文)占据 8K字节的节目空间。对于可以编译定义的完整内核, 您应该允许最少1K字节的RAM。使用'块管理 用于磁盘存储系统,您应该为缓冲区添加3 kBytes或更多。为了 32位模型,双倍这些数字。

这些是最低次数和运行的最低限度。 要在硬件上运行应用程序,您应该增加舞会和公羊 尺寸适合。

使用的单词尺寸不一定与之相同 中央处理器。最小的实际索引是一个16位模型;即,使用一个 16位整数和16位地址。四个社区称之为 "细胞"大小,自从#34; Word"指的是第四个定义。

8位CPU几乎总是支持16位。这通常需要 双字节算术的显式编码,虽然有一些8位CPU 有几个16位操作。

16位CPU通常运行16位,虽然是相同的双精度 可以使用技术在16位CPU上写入32位。至少 为8086/8088编写了一个32位。

32位CPU通常运行32位。较小的模型很少 保存代码长度或处理器时间。但是,我知道至少有一个16位 为68000编写的。这确实收缩了应用程序代码大小 由于两个倍数,因为高级别的定义成为一个字符串 16位地址而不是32位地址的字符串。 (这会 很快就变得明显。)大多数68000岁,有很多RAM。

本文中描述的所有示例都是16位运行 在8位CPU上。

"线程代码"是标志的标志。 Xthapt"线程" 只是要执行的例程的地址列表。你可以想到 这是子程序调用列表,删除了呼叫指令。 多年来,已经设计了许多穿线变化,哪一个 最好取决于CPU和应用程序。做出决定,你 需要了解他们的工作方式以及他们的权衡。

这是典型的螺纹技术,用于代表 和F83,并在大多数书籍中描述。所有其他螺纹 方案是"改进"在这方面,所以你需要了解 ITC欣赏他人。

在典型的ITC中,这将出现在内存中,如图所示 1.(标题将在未来的文章中讨论;它持有家务 用于编译的信息,以及涉及穿线的ISN')

在执行其他一些单词时遇到广场。 ' S解释器指针(IP)将指向内存中的单元格 - 包含在该&#34之内;其他"单词 - 包含地址 字广场。 (要精确,那个细胞包含广场的地址' s 代码字段。)解释器获取该地址,然后使用它 获取Square' s代码字段的内容。这些内容又是另一个 地址 - 执行的机器语言子程序的地址 字广场。在伪代码中,这是:

(IP) - > w获取IP进入" W"登记 ... W现在保存代码字段的地址 IP + 2 - > IP affign ip,就像一个程序计数器 (假设线程中的2字节地址) (w) - > X由W引入" x"登记 ... x现在包含机器代码的地址 jp(x)跳转到x寄存器中的地址

这说明了重要但很少被阐明的原则: 刚输入的第四个词的地址被保存在W.代码词不' t 需要这些信息,但所有其他类型的词语都这样做。

如果广场是用机器代码编写的,这将是结束 故事:将执行那么一点机器代码,然后跳回到 第四解释器 - 由于IP递增,所以指向 要执行的下一个单词。这就是为什么第四解释器 通常被称为下一个。

但是,广场是一个高级别的"冒号"定义 - 它持有 A"线程",地址列表。为了执行这个定义, 必须在新位置重新启动第四解释器:参数 广场领域。当然,翻译'旧位置必须保存, 恢复"其他"一旦Square完成了一个单词。这 就像一个子程序电话!方形的机器语言动作是 只需将旧IP推动,将IP设置为新位置,运行解释器, 当Square完成时,弹出IP。 (正如您所看到的,IP是"程序 柜台"高级别。)这被称为Docolon或进入 各种各样的:

将IP推入"返回地址堆栈" W + 2 - > IP W仍然指向代码字段,因此W + 2是 身体的地址! (假设一个2字节 地址 - 其他可能是不同的。) 跳转到翻译("下一个")

所有高级(即,螺纹)使用该相同的代码片段 第四个定义!那个'为什么指向这个代码片段的指针,而不是 片段本身,包括在第四个定义中。超过数百人 定义,储蓄加起来!这就是为什么它' s被称为间接线程。

和#34;从子程序返回和#34;是退出这个词,得到了 汇编什么时候&#39 ;;' (有的话称之为; s而不是退出。) 退出只执行机器语言例程,执行以下操作:

走过几个嵌套的定义,只是为了保证自己 这是有效的。

注意ITC的特征:每一个单词都有一个细胞 代码字段。冒号定义编译一个用于每个单词的一个单元格 定义。而第四个翻译必须实际执行双重 间接获取下一台机器代码的地址运行(首先通过 IP,然后通过w)。

ITC既不是最小,也不是最快的线程技术。它 可能是最简单的;虽然DTC(下一个描述)真的没有更复杂。 那么为什么这么多的间接线程?主要是因为以前 用作模型的索斯是间接的。这几天,DTC正在变成 更流行。

所以应该什么时候使用ITC?各种技术,ITC产生 最干净,最优雅的定义 - 除了地址。如果 您'重新调整此类考虑因素,ITC可能会对您诉争。如果您的代码 用定义的内部,简单和均匀的内部摆弄 ITC表示可能提高可移植性。 ITC是古典的 模型,所以可能是教育的首选。最后,关于CPU缺乏 子程序调用指令 - 例如1802 - ITC通常更多 高于DTC。

直接线程代码与ITC的不同之处在于一个方面:代替 包含某些机器代码的地址,代码的代码字段 字段包含实际的机器代码本身。

我并不是说每个输入的完整代码都包含在每个输入 和每个冒号定义! "高级"单词, 代码字段将包含子程序调用,如图2所示。 例如,冒号定义将包含对Enter例程的调用。

(IP) - > w获取IP进入" W"登记 IP + 2 - > IP affign ip(假设2字节地址) JP(W)跳转到W寄存器中的地址

这个收益速度:翻译现在只表现为单一 间接。在z80上,这减少了下一个例程 - 最常用的例程 代码片段在第一个内核 - 从11指令到七!

这个成本空间:Z80中的每个高级定义(例如) 现在是一个字节更长的,因为2字节地址已被3字节替换 称呼。但这不是普遍的真实。可以是32位68000秒 用4字节BSR指令替换4字节地址,无净损耗。 在Zilog Super8上,它具有DTC的机器指令, 2字节地址由1字节输入指令替换,制作一个字节 DTC在Super8上较小!

当然,DTC代码定义是两个字节较短,因为它们没有 一直需要一个指针!

我曾经认为DTC索斯中的高级定义需要 在代码字段中使用子程序调用。 Frank Sergeant' S Pygmy Forth [SER90]展示了简单的跳跃可以容易地使用 通常会更快。

Guy Kelly已经编制了一个卓越的审查,以实现 IBM PC [KEL92],我强烈推荐全部内核 作家。在他学习的19个鼻胎中,10次使用的DTC,7用ITC,2使用 子程序线程(接下来讨论)。我建议使用直接线程 代码全新内核的间接线程代码。

Next Inner Interpreter,接下来,是所有代码定义的常用例程。 您可能只保留一个常见例程的一份副本,并拥有所有代码 单词跳到它。 (请注意,您跳转到下一个;子程序呼叫不是 必要的。)

然而,接下来的速度对整个右的速度至关重要 系统。此外,在许多CPU上,下一个例程很短;常有 两三个指示。因此,可以更优选地在线编码, 无论使用它。这通常是通过使汇编程序进行下一个汇编程序来完成 宏。

这是一个简单的速度与空间决定:在线下一步总是更快, 但几乎总是更大。总尺寸增加是额外数量 在线扩展所需的字节,代码单词的数量 系统。有时候''否则没有权衡:在6809 dtc, 在线接下来比跳跃指令短!

高级别的定义只不过是子程序列表 被执行。你不需要口译员来完成这一点;你可以得到 通过简单地串入子程序调用的列表在一起来实现相同的效果:

请参见图3.此表示的表示已被用作 起点以向汇编语言解释线程技术 程序员[Kog82]。

STC是优雅的代表;冒号定义和代码词是 现在相同。 "定义的单词" (变量,常数和 喜欢)处理与DTC中的相同 - 代码字段以跳转开始 或致电其他地方的机器代码。

主要缺点是子程序呼叫通常大于 简单的地址。例如,在Z80上,冒号定义的大小 增加50% - 您的大部分申请是结肠定义! 相反,在32位68000上,可能没有尺寸增加,何时 4字节地址用4字节BSR替换。 (但如果您的代码大小 超过64K,其中一些地址必须用6字节JSR替换。)

子程序线程可能比直接线程更快。你 通过没有翻译,但你会省时间,但你失去了时间 参考题词涉及返回地址的推送和流行。 在DTC中,只有高级单词导致返回堆栈的活动。 在6809或Zilog Super8上,DTC比STC快。

STC还有另一个优势:它可以使用IP寄存器分配。 一些处理器 - 就像8051 - 拼命地缺乏寻址 寄存器。消除IP可以真正简化和加速内核!

知道的唯一方法是编写示例代码。这是 密切参与注册选择,在下一节中讨论。

在较旧的和8位CPU上,几乎每个迫征原语都涉及几个 机器指令。但是在更强大的CPU,许多迫切的原语 用单一的指令写。例如,在32位68000上, 下降就是简单的

在子程序中,在冒号定义中使用下降 导致序列

AddQ是一个双字节指令。为什么写一个四字节的子程序调用 到一个双字节指令?无论使用多少次下降,那么都有 没有储蓄!如果addq直接编码,则代码较小,更快 进入BSR的流。一些第四个编译器做到这一点"在线扩展" 代码词[cur93a]。

在线扩展的缺点是重复回复 原始源代码变得非常困难。只要子程序调用 使用,您仍然有指针(子程序地址)到第四个 包括螺纹的单词。用指针到单词,你可以获得 他们的名字。但是一旦一个词被扩展到英式编码,所有知识 在哪里丢失了那个代码。

一线扩展的优势 - 除了速度和尺寸 - 是 代码优化的可能性。例如,第四个序列

优化编译器对于本文来说太广泛了。这 是一个活跃的领域研究;例如,参见[SCO89] 和[cur93b]。优化的STC的最终高潮是第四组成的 "纯"机器代码,就像一个c或fortran编译器。

DTC和STC的旨在提高速度的速度,以某种成本 在记忆中。现在让' s从ITC的另一个方向移动,朝向某事 较慢但更小。

第四个线程的目的是指定一个列表(子例程) 要进行。假设16位系统最多只有256个 不同的单词。然后每个单词都可以唯一地识别8位 数字。您将列出列表而不是16位地址列表 8位标识符或"令牌,"和冒号定义的大小 会减半!

一个令牌线程,保留了一张地址的字样, 如图4所示。然后令牌值用于索引到此表中, 找到与给定令牌对应的字。这增加了 四个间接的间接级别,所以它比慢于 一个"地址线程和#34;向前。

令牌螺纹的主要优点是小尺寸。 TTC. 最常见于掌上电脑和其他严重尺寸约束的 应用程序。此外,表格"入口点"进入所有 四个词可以简化单独编译模块的链接。

TTC的缺点是速度:TTC使得最慢。还, TTC编译器稍微复杂。如果您需要超过256秒 单词,它'必须具有一些开放式编码方案来混合8位 和较大的令牌。

我可以使用16位令牌设想32位,但是有多少32位 系统是尺寸约束的?

由于世界上有这么多8086衍生物,段线程 值得简要提及。而不是使用"正常"字节地址 在64K段内,使用段落地址。 (A"段落" 在8086中是16个字节。)然后,解释器可以加载这些地址 进入段寄存器,而不是进入通常的地址寄存器。这 允许16位模型可以有效地访问完整的兆字节 8086内存。

段线程的主要缺点是16字节"粒度" 记忆空间。每一个字必须与16字节的边界对齐。 如果该词具有随机长度,则将浪费平均8个字节 过了一词。

在线程技术旁边,CPU'寄存器的使用是 最重要的设计决定。它可能是最困难的&#39。这 CPU寄存器的可用性可以确定哪种线程技术可以 使用,甚至存储器地图将是什么!

经典的模型有五个"虚拟寄存器。"这些 是在原始操作中使用的抽象实体。 接下来,在这些抽象寄存器方面先定义了输入和退出。

这些中的每一个都是一个细胞宽 - 即,在16位,这些是 16位寄存器。 (此规则存在异常,正如您稍后会看到的那样。) 这些可能并非全部都是CPU寄存器。如果您的CPU没有足够的' 寄存器,其中一些可以保存在内存中。我' ll描述它们 他们重要的顺序;即,此列表的底部是最好的候选人 存储在内存中。

w是工作登记册。它用于许多东西,包括 内存参考,所以它应该是地址寄存器;即,你必须是 能够使用W作为地址的内容来获取和存储内存。 您还需要能够在W算术上进行算术。(在DTC中,您必须 也能够使用w跳跃间接。)w被解释器使用 每一个词。在一个只有一个寄存器的CPU中,您将使用 它是w,并在内存中保留其他一切(并且系统将是令人难以置信的 慢的)。

IP是解释器指针。这是通过电流使用的 Word(通过下一个,输入或退出)。 IP必须是地址寄存器。 您还需要能够递增IP。子程序穿过右侧' t 需要这个寄存器。

PSP是参数堆栈(或"数据堆栈")指针, 有时被称为sp。我更喜欢PSP,因为SP经常是名称 CPU寄存器,他们应该困惑。大多数代码单词使用 这。 PSP必须是堆栈指针,或可以是的地址寄存器 递增和递减。它也是一个加号,如果你可以做索引的寻址 来自PSP。

RSP是返回堆栈指针,有时叫做RP。 这是由ITC和DTC的冒号定义使用,并通过所有 在STC中的单词。 RSP必须是堆栈指针或地址寄存器 可以递增和递减。

如果可能,请在寄存器中放置W,IP,PSP和RSP。这 遵循的虚拟寄存器可以保存在内存中,但通常有 将它们保持在CPU寄存器中的速度优势。

X是一个工作寄存器,不被视为"古典" 即使经典的ITC第四个需要它,即使是第二个 间接。在ITC中,您必须能够使用x跳跃间接。x也可以 通过几个代码单词使用来执行算术。这是特别的 对无法使用内存作为操作数的处理器很重要。例如, 添加z80可能是(在伪代码中)

UP是用户指针,持有任务的基础地址' s 用户区域。 UP通常被添加到偏移量,并由高级别使用 代码,所以它可以刚刚存储在某处。但如果CPU可以索引 从向上寄存器寻址,代码词可以更容易且快速 访问用户变量。如果您有剩余的地址寄存器,请使用 一个人。单项任务第四次不需要'

X - 如果需要 - 更重要的是保持登记。向上 是第四个虚拟寄存器中最容易进入内存的寄存器。

大多数CPU都有一个堆栈指针作为其硬件的一部分,由中断使用 和子程序调用。该地图如何进入Forth寄存器?应该 这是PSP还是RSP?

短暂的答案是,它取决于。据说使用了PSP 超过ITC和DTC的RSP。如果您的CPU很少

......