【问题标题】:Seeing how Instructions get Translated (Computer Architecture)了解指令如何被翻译(计算机体系结构)
【发布时间】:2013-04-11 13:28:07
【问题描述】:

有点令人困惑的问题。但我真的想学习一些低级编程。事情是,像 Arduino/Etc 这样的开发板。真的隐藏了很多正在发生的事情。

我花了一些时间学习计算机体系结构、逻辑/门/顺序逻辑等。(我什至还学习了与之相关的半导体物理学和电子学,只是为了知道到底发生了什么关于,以及如何使用 CMOS 晶体管等制造门)。

但这就是它结束的地方......我希望能够理解指令(如十六进制/或汇编/等代码)如何通过尽可能简单的计算机(我有很多书)我曾经直接从盖茨之类的电脑变成了电脑……没有真正的介于两者之间)。甚至是一些简单的事情,比如......将值存储在寄存器或内存位置(可能打印到像素?或其他东西)。

我认为最终可能会写一个模拟器会很有趣。我有高级语言的经验,但我听说像 6502 之类的东西可能是一个好的开始,因为你使用了很多汇编,而且指令集不是太大。

有没有人知道任何可能有帮助的资源/想法/书籍?我已经阅读了“计算系统要素”,虽然......这是一本好书,但我并没有真正觉得它经历了真​​正发生的事情并看到它发生。这可能更像是一个 Electronics.stackexchange 问题,如果是这样,我深表歉意。

【问题讨论】:

  • @dwelch 谢谢我看看这些,理想情况下我的第一个任务是真正了解其中的计算机架构部分,但是从它进入模拟器/模拟器会非常有帮助。我会定义的。为您的页面添加书签!
  • @dwelch 同意,这将是一个漫长的过程,但这是我一直想学习的东西。我一直在研究一些 SAP 计算机架构设计,以了解与寄存器/内存等交互的感觉。我认为这是一个不错的开始。我听说 CHIP-8 的一些优点也很容易模仿。
  • 我猜你描述的第一部分......我不太确定从哪里开始。我对典型架构的外观有所了解,但我想不太确定要寻找什么?
  • 哇,感谢您提供的所有信息。我想我至少掌握了入门所需的信息。我想我会从 6502 开始,然后可能是 MIPS,因为它们似乎都有很多文档。谢谢!

标签: assembly embedded emulation computer-architecture 6502


【解决方案1】:

概述

你真的有很多选择。我将总结我对如何翻译指令的看法,但我也会提供一些我开始时的选择。

我的看法

首先,从二进制输入的角度来思考是最容易的。假设您有一个 16 位微处理器。 (也就是说,指令以 16 位二进制编码。)考虑一个将数字放入寄存器的汇编操作 SET。例如:

SET(R1, 12) // Stores 12 into register 1

让我们任意选择(因为即使在任何标准架构中,选择也确实是任意的)选择将 SET 指令翻译成以下 16 位二进制值 I:

0001 0001 0000 1100

基本上,我只是制定了一个约定。但这里是我如何分解它。我选择让位 I[15:12](以big-endian 表示法表示)表示特定指令。我选择让整数1对应指令SET。现在我已经决定了那个约定,我可以说如果我有一个 SET 指令,让位 I[11:8] 对应于寄存器。 (显然这意味着我将只有 16 个寄存器:4^2=16)。最后,我让位 I[7:0] 对应于我要存储在给定寄存器中的数据。让我们再看一下二进制的 SET(R1, 12) (为了清楚起见,我用换行符分隔每组四个):

if I =  0001 0001 0000 1100
I[15:12] = 0001 (binary) = 1 (decimal) = SET instruction
I[11:8] = 0001 (binary) = 1 (decimal) = R1 since I[15:12] correspond to SET.
I[7:0] = 0000 1100 (8-bit binary) = 12 (decimal) = value to store in R1.

如您所见,微处理器中的其他一切都变得非常简单。假设您在 RAM 中存储 4 行指令。你有一个附在时钟上的计数器。计数器通过 RAM 中的行计数。当时钟“滴答”时,一条新指令从内存中出来。 (即 next 指令来自 RAM - 尽管一旦插入 JUMP 语句这可能有点随意。) RAM 的输出通过多个位选择器。您选择位 I[15:12] 并将它们发送到控制单元 (CLU),该控制单元 (CLU) 会告诉您 要传达的指令是什么。 IE。 SET、JUMP 等。然后根据找到的指令,您可以决定允许写入寄存器或添加寄存器,或者您选择在架构中包含的任何其他内容。

现在幸运的是,已经为您选择了机器指令二进制值的任意约定(如果您想遵循它们)。这正是由指令集架构 (ISA) 定义的。例如MIPSHERA 等。为了清楚起见,您在设计电路时创建的实际实现被称为微架构

学习资源

文字

Harris and Harris 书是本科计算机体系结构课程最著名的教材之一。这是一个非常简单和有用的文本。一些随机学校免费提供了 PDF here 的全部内容。 (快速下载!)我发现它非常有帮助。它涵盖了基本电路、离散数学主题,当你读到第 7 章时,构建微处理器已经是小菜一碟了。读完那本书后,我花了大约 3 天时间完成了一个 16 位微处理器。 (当然,我有离散数学的背景,但这并不是很重要。)

另一本超级有用且非常标准的书是Hennessy and Patterson 书,从一些随机学校以 PDF 形式提供。 (快速下载!)哈里斯和哈里斯的书是基于这本书的简化。这本书更详细。

开源微处理器

那里有大量的开源微处理器。当我构建我的第一个微处理器时,能够参考它们对我非常有帮助。带有 Logisim 文件的文件特别好用,因为您可以以图形方式查看它们,然后像​​这样单击并弄乱它们。以下是一些我最喜欢的网站和特定的 mps:

4 位:

16 位:

Open Cores - 我真的不明白这个网站。我申请了一个帐户,但他们还没有真正回来……不是一个忠实的粉丝,但我想如果你有一个帐户,那一定很棒。

工具

逻辑模拟

如前所述,Logisim 是一个很好的资源。布局完全是图形化的,您可以通过选择一条线很容易地在任何时间点按位查看正在发生的事情。它是用 Java 编写的,所以我很确定它可以在您想要的任何机器上运行。这也是图形计算机编程语言的一个有趣的历史视角。

模拟

在 Logisim 中,您可以模拟正在运行的实际软件。如果您有一个编译器可以将二进制文件编译到您的目标 ISA,那么您可以简单地将二进制文件或十六进制文件加载到 Logisim RAM 中并运行程序。 (如果你没有编译器,编写一个四行汇编程序并自己手动翻译它仍然是可能的,也是一个很好的练习。)模拟是整个过程中最酷和最令人满意的部分! :D Logisim 还提供了一个CLI 用于以编程方式执行此操作。

高密度脂蛋白

生成/设计微架构的更现代形式是使用硬件描述语言 (HDL)。最著名的例子包括 Verilog 和 VHDL。这些通常(令人困惑!)以 Ada 和 C/C++ 等顺序语言为模型。然而,这是迄今为止首选的设计方法,因为模型/设计的验证得到了更好的定义。在我看来,推理文本表示比用图形检查要容易得多。正如程序员不能很好地组织代码一样,硬件开发人员也不能很好地组织微架构图形设计的图形布局。 (尽管这个论点当然可以应用于 HDL。)以文本方式记录比以图形方式记录更容易,并且通常使用 HDL 进行更模块化的设计。

如果您有兴趣学习这一点,这里有大量的本科硬件课程,包括开放课程和实验室工作,讨论和学习如何使用 HDL 描述电路和微架构。你可以通过谷歌搜索找到这些。或者您也可以尝试通过下一步学习 HDL - 将 C/C++ 代码转换为 HDL 的工具。如果您有兴趣,那么Icarus Verilog 是一个很好的 Verilog 开源编译器和模拟器。

模拟

使用 Icarus Verilog 之类的工具,您还可以轻松模拟从二进制文件运行的真实程序。您只需将微处理器包装在另一个 Verilog 脚本中,该脚本通过某些总线将文件或字符串加载到 RAM 中。小菜一碟! :D

HLS

近年来,High Level Synthesis (HLS) 也在市场上获得了significant 的立足点。这是将 C/C++ 代码转换为实际电路的过程。这非常不可思议,因为现有的 C/C++ 可以(但不总是)转换为硬件。

(我说并非总是如此,因为并非所有 C/C++ 代码都是可合成的。在电路中,比特流同时存在于任何地方。在软件中,我们认为代码是连续的。这是如果你正在尝试设计硬件,这是一种糟糕的思考模式!!)

但正如您可能猜到的那样,这种能力对于优化硬件上代码的某些方面(例如矩阵运算或一般数学)来说是不可思议的。但是,这与您相关,因为您可以使用 HLS 工具查看如何将点积的 C 实现(例如)转换为 HDL。我个人觉得这是一种很好的学习方式。

模拟

HLS 模拟与模拟 HDL 一样简单,因为高级代码只是简单地转换为 HDL。然后你可以完全按照我上面的解释来模拟和运行测试。

【讨论】:

    【解决方案2】:

    麻省理工学院将其计算结构课程 6.004 的所有资源放到网上。它本质上是一个计算机体系结构简介课程,非常注重基于项目的学习。

    OpenCourseWare 版本是here。我会特别关注labs,尤其是 2、3、5 和 6,它们将带您从构建加法器到 ALU 一直到非常简单的处理器(Beta)。

    最新课程资料的链接是here

    我记得当我上这门课时,第一次在理解简单的逻辑门和电子元件如何转化为我用来模拟它的复杂机器方面,一切都“点击”了。强烈推荐的资源。

    【讨论】:

      【解决方案3】:

      The Art of Assembly Language 的前几章讨论了如何使用锁存器物理存储位,并介绍了如何使用锁存器来组装寄存器以保存数据字节以及如何在硬件中实现诸如左/右移位之类的指令。可能没有你想要的那么深入,但当我读到这些东西时,它真的让我大开眼界。

      【讨论】:

        【解决方案4】:

        这是一个非常简单的 6502 指令集模拟器的示例框架(因为您不止一次提到 6502)。它从一个简单的 6502 程序开始,这些是我将要演示的唯一说明,但即使使用这样的程序,您也可以理解并立即感到满意。

           and #$00
           ora #$01
         top:
           rol
           bcc top
           and #$00
        

        是的,我很清楚我没有正确启动模拟器。我假设这个二进制文件基于地址零,使用 xa65 汇编程序(apt-get install xa65)。组装后的二进制是:

        hexdump -C a.o65 
        00000000  29 00 09 01 2a 90 fd 29  00                       |)...*..).|
        00000009
        

        这是简单的简化指令,模拟器

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        
        FILE *fp;
        
        #define MEMMASK 0xFFFF
        unsigned char mem[MEMMASK+1];
        
        unsigned short pc;
        unsigned short dest;
        unsigned char a;
        unsigned char x;
        unsigned char y;
        unsigned char sr;
        unsigned char sp;
        unsigned char opcode;
        unsigned char operand;
        
        unsigned char temp;
        
        int main ( void )
        {
            memset(mem,0xFF,sizeof(mem)); //if we execute a 0xFF just exit
        
            fp=fopen("a.o65","rb");
            if(fp==NULL) return(1);
            fread(mem,1,sizeof(mem),fp);
            fclose(fp);
        
            //reset the cpu
            pc=0; //I know this is not right!
            a=0;
            x=0;
            y=0;
            sr=0;
            sp=0;
            //go
            while(1)
            {
                opcode=mem[pc];
                printf("\n0x%04X: 0x%02X\n",pc,opcode);
                pc++;
                if(opcode==0x29) //and
                {
                    operand=mem[pc];
                    printf("0x%04X: 0x%02X\n",pc,operand);
                    pc++;
                    printf("and #$%02X\n",operand);
                    a&=operand;
                    if(a==0) sr|=2; else sr&=(~2);
                    sr&=0x7F; sr|=a&0x80;
                    printf("a = $%02X sr = $%02X\n",a,sr);
                    continue;
                }
                if(opcode==0x09) //ora
                {
                    operand=mem[pc];
                    printf("0x%04X: 0x%02X\n",pc,operand);
                    pc++;
                    printf("ora #$%02X\n",operand);
                    a|=operand;
                    if(a==0) sr|=2; else sr&=(~2);
                    sr&=0x7F; sr|=a&0x80;
                    printf("a = $%02X sr = $%02X\n",a,sr);
                    continue;
                }
                if(opcode==0x2A) //rol
                {
                    printf("rol\n");
                    temp=a;
                    a<<=1;
                    a|=sr&0x01;
                    sr&=(~0x01); if(temp&0x80) sr|=0x01;
                    if(a==0) sr|=2; else sr&=(~2);
                    sr&=0x7F; sr|=a&0x80;
                    printf("a = $%02X sr = $%02X\n",a,sr);
                    continue;
                }
                if(opcode==0x90) //bcc
                {
                    operand=mem[pc];
                    printf("0x%04X: 0x%02X\n",pc,operand);
                    pc++;
                    dest=operand;
                    if(dest&0x80) dest|=0xFF00;
                    dest+=pc;
                    printf("bcc #$%04X\n",dest);
                    if(sr&1)
                    {
                    }
                    else
                    {
                        pc=dest;
                    }
                    continue;
                }
                printf("UNKNOWN OPCODE\n");
                break;
            }
            return(0);
        }
        

        以及那个简单程序的模拟器输出。

        0x0000: 0x29
        0x0001: 0x00
        and #$00
        a = $00 sr = $02
        
        0x0002: 0x09
        0x0003: 0x01
        ora #$01
        a = $01 sr = $00
        
        0x0004: 0x2A
        rol
        a = $02 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $04 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $08 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $10 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $20 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $40 sr = $00
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $80 sr = $80
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0004: 0x2A
        rol
        a = $00 sr = $03
        
        0x0005: 0x90
        0x0006: 0xFD
        bcc #$0004
        
        0x0007: 0x29
        0x0008: 0x00
        and #$00
        a = $00 sr = $03
        
        0x0009: 0xFF
        UNKNOWN OPCODE
        

        如果您从头开始编写完整的 6502 指令集,那么它是一个长周末的最低工作量,因为您发现您可能最终会重新启动项目几次,非常自然。处理器的硬件(通常,不一定是 6502)在概念上与模拟器中发生的事情并没有太大的不同。您必须获取指令、解码指令、获取操作数、执行并保存结果。就像在软件中执行此操作一样,在硬件中,您可以创建有趣的方法来使其更快或更小或任何您的目标。

        6502 仍然是一个大项目,如果你实现整个东西,不如 z80 大,但是像 risc16 这样的东西可能需要半个小时来理解和编写整个模拟器(然后再花半个小时来制作一个汇编器)。 pic12、14 或 16 的工作量比 risc16 多,但也不算多,可以快速完成它,并且是一种设计简单的教育体验。 pdp11 和 msp430 毫无疑问在某种程度上是相关的,两者都有很好的记录(我提到的所有这些都有很好的记录)并且很好/大部分是正交的,并且类似 RISC 的解码与像 6502/z80/x86 这样的 cisc 是不同的体验。 (gcc/gnu 工具原生支持 pdp11)。如果您可以围绕分支延迟槽运行算法,那么 Mips 非常简单。

        祝你好运,玩得开心......

        【讨论】:

          【解决方案5】:

          Noam Nisan 和 Shimon Schocken 2005 年 ISBN 9780262640688 编写的计算系统的元素 是一本带您逐步从大门到功能齐全的计算机的文本。他们的网站位于 @987654321 @

          【讨论】:

            【解决方案6】:

            尝试构建自己的简单 CPU。它并不像看起来那么难: LOGISIM

            【讨论】:

            • 如果你愿意,我可以帮助你。请给我发个 PM。
            • 是的,构建一个非常简单的 CPU 似乎会有所帮助。那是我的想法。即使在模拟器上。一步一步地设计一台电脑....会很棒。
            猜你喜欢
            • 1970-01-01
            • 2012-03-28
            • 1970-01-01
            • 1970-01-01
            • 2015-05-18
            • 1970-01-01
            • 1970-01-01
            • 2017-06-14
            • 2014-07-06
            相关资源
            最近更新 更多