【问题标题】:How does one learn to program game console emulators (hardware knowledge specifically)? [closed]一个人如何学习对游戏机模拟器进行编程(特别是硬件知识)? [关闭]
【发布时间】:2012-10-19 02:19:49
【问题描述】:

我之前问过一个类似的问题,关于如何编写模拟器,当我看到答案并查找了一些开源的 gameboy 模拟器时,我发现除了对“低级”语言(即C)。我真正想知道的是,我需要了解有关硬件的什么信息才能对这样的模拟器进行编程。我正在接近在 Java 上“相当不错”,但这对我没有多大帮助。我已经开始学习 C 并且现在已经走了很长一段路,但是我很想知道我必须在硬件中学习什么才能编写这样的控制台模拟器。

我问这个问题的原因是我一直在互联网上搜索有关仿真的书籍和资源,每当我遇到仿真器教程时,它总是像“你需要对 C 有基本的了解才能成为能够遵循本教程”,当我尝试遵循它时,我不能,仅仅是因为我不知道到底在编程什么。我对硬件一无所知。 (我父亲在将显示器连接到 PC 时遇到困难,可能对此了解更多)

所以我的问题是,我需要学习什么(微处理器、内存等?),是否有任何好的资源可以教我这些东西,而无需我上大学或其他东西(已经做软件工程)?

如果这不是一个真正的问题,或者不够清楚,或者类似的问题,我深表歉意。我只是对这个主题很感兴趣。

【问题讨论】:

  • 我已经读过,虽然它包含了很多有用的信息,但唯一具体说明需要哪些硬件知识的是“微处理器”。我假设游戏机不仅包含 1 个微处理器?这是学习如何编写模拟器唯一需要的东西吗? (我知道这听起来很愚蠢,但请耐心等待)
  • 基本上,您需要了解关于对您正在模拟的设备进行编程的一切:您需要了解它的汇编语言,以及与您的所有外围设备的硬件接口需要模拟,特别是它的显示子系统的所有原始毛茸茸的细节,如果它有操作系统的话——作品!如果您发现按指令解释指令的效率不够高,那么一般而言,良好的编译器构造基础也将非常有用。

标签: c console hardware emulation video-game-consoles


【解决方案1】:

首先,对模拟器进行编程需要多个领域的知识。您需要牢牢掌握的两大领域是计算机体系结构和您选择的编程语言。如果您根本没有编程经验,那么创建模拟器并不是一个好主意。话虽如此,只要您熟悉它,您就可以使用任何您想要的语言创建模拟器!

为了了解系统的工作原理,建议您复习一下计算机体系结构。我建议阅读一本关于该主题的好书,例如Computer Architecture: A Quantitative Approach,这对于大多数建筑课程来说是一本很常见的书。

一旦您对系统的运行方式(CPU、内存、寄存器、指令集等)有了实际的(基本)知识,您就可以尝试模拟您选择的系统。在这个阶段,我建议尽可能多地挖掘有关您选择的系统的信息。 Zophar.net 收集了大量有关许多视频游戏机的技术文档。

一旦您对要模拟的系统有所了解,我建议您编写代码来读取 ROM 文件并提取文件内容(特别是说明)。下一步是模拟架构的 CPU 并为每条指令编写处理程序。我通过在从 ROM 加载的实际指令上运行 CPU 来测试 CPU。在您实现了大量指令后,您可以开始实现其他子系统,例如图形和事件/中断系统。我通常实施的最终系统是健全的。

(无耻的插件)我在一本名为Emulation - Step by Step 的书中写了更多关于这一切的内容,我希望在几个月内出版。我还没有看到关于这个主题的另一本书,这很可耻,因为它是一个非常有趣的话题!

【讨论】:

    【解决方案2】:

    如果如您所说,您对硬件一无所知,那么编写仿真器将不是一件容易的事。了解硬件的基本功能可能比了解任何特定的编程语言更有意义。

    我可以推荐 Noam Nisan 和 Shimon Schocken 的书计算系统的元素 及其相关的互联网资源 (http://www.nand2tetris.org/)。本书将带您从简单的与非门到构建功能计算机,然后到编写汇编程序、编译器和操作系统,最后是俄罗斯方块游戏。在每个级别,您都可以“构建自己的”或使用网络上可用的答案来构建下一个级别。

    【讨论】:

      【解决方案3】:

      认为这可能更适合programmers.stackexchange.com,但无论如何:

      我不会说您需要任何特定知识。了解微处理器和内存管理的工作原理以及汇编程序知识将有很大帮助(因为您实际上是在为类似汇编程序的代码编写解释器)。假设您已经知道目标硬件的工作原理,那么您基本上需要做的就是实现以下组件(即伪造真实硬件并模仿/模拟其行为):

      • 模拟 CPU 解析和运行机器代码。
      • 模拟输入组件(将键盘、鼠标或操纵杆输入转换为 CPU 可访问的“引脚信号”)。
      • 模拟输出组件(将图像和音频数据转换为可见的内容,例如在屏幕上显示某些内容或生成类似于真实硬件组件的声音)。
      • 模拟其他组件,如内存包、内置电池、墨盒、扩展芯片等。

      作为一般建议,我会说暂时忘记编写任何模拟器。而是从尝试编写自己的字节码解释器开始。

      例如,您可以使用一个简单的伪代码序列:

      x = 5
      y = 10
      print(x + y)
      

      用伪汇编编写,可能是这样的:

      mov x, 5
      mov y, 10
      add x, y // to be honest, this is essentially x += y; not just x + y
      prt x
      end
      

      现在用(代码)数字替换所有指令。所有变量都替换为数字:

      0x01 0x00 0x05
      0x01 0x01 0x0a
      0x02 0x00 0x01
      0x03 0x00
      0x00
      

      这可能看起来有点奇怪,但我保留了上面的顺序和换行符。请注意,我在第一条指令中使用了0x01,而不是0x00。这只是为了方便,所以我可以将0x00 用于“NOOP/no operation”或作为终止符(如本例所示)。现在只需删除换行符,您就基本上得到了自定义字节码。

      char code[] = {0x01, 0x00, 0x05, 0x01, 0x01, 0x0a, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00};
      

      要运行此代码,您可以编写一个简单的“模拟器”。它只有一个有限的指令集,但它会工作。我实际上没有测试这段代码,所以请记住,我可能在某些时候搞砸了。然而,它应该足以让您了解如何/做什么。请注意,在此示例中,我没有拆分数据存储器和指令存储器。这会增加更多目前并不真正需要的复杂性。

      int pos = 0; // essentially being our "instruction pointer"
      char registers[10];
      while(code[pos]) { // still some instruction
          switch(code[pos++]) { // determine what to do and move the instruction pointer
          // 0x00 isn't handled here, as that's part of our loop already
          case 0x01: // mov(e)
              registers[code[pos++]] = code[pos++]; // read the value into the register
              break;
          case 0x02: // add
              registers[code[pos++]] += registers[code[pos++]];
              break;
          case 0x03: // prn
              printf("%d", registers[code[pos++]]);
              break;
          }
      }
      

      一旦您了解了我在这里所做的事情,我很确定您应该也可以更轻松地了解其他来源。哦,还有一个有趣的事实:如果您这样做是为了教育目的,而不仅仅是为了编写一个高效的模拟器,您可以开始使用 Java。它会不太理想且速度较慢,但​​您基本上可以做同样的事情,甚至可能至少消除您路上的障碍。

      请注意:在上面的示例中,您可以有第二个线程不断地在屏幕上写入registers[] 的内容。通过这种方式,您基本上可以模拟一些视频硬件(例如电视屏幕或 LED)。

      如果您正在寻找更多要阅读的资源,我会尝试使用一些简单的处理器并开始学习汇编代码。如果可能,选择一个非常简单的架构。概念总是相同的,但随着指令集、地址空间虚拟化等越来越多,事情可能会变得复杂。

      【讨论】:

      • 谢谢伙计,我爱你,你是一个绝对的英雄,你花时间向我详细解释这一点:D
      【解决方案4】:

      我建议学习一门汇编语言来获得你需要的基础知识。如果您对超级 nintnedo 等感兴趣,您可以尝试学习 65816-assembly,这是该控制台使用的处理器的汇编语言。要开始,您可以从这里开始阅读:http://en.wikibooks.org/wiki/Super_NES_Programming。其他控制台也存在类似的资源。我还建议使用具有调试功能的模拟器,例如 Geiger 的调试 snes9x,它可以让您逐步执行游戏,转储正在执行的操作,检查内存等。虽然这些都与编写控制台没有直接关系模拟器,它会给你一些你正在寻找的背景。

      说实话,如果 C 对您来说完全陌生,那么在尝试汇编之前最好先学习一些。 C 比汇编抽象得多,但仍会为您提供许多重要概念的基础,最重要的是指针。

      但基本上,模拟器所做的是单步调试游戏的机器代码,逐条执行。控制台是一个相当复杂的野兽,有多个处理器和协处理器以及相关的硬件协同工作。所以你可能应该从一个更简单的模拟器开始,它只模拟 CPU,而忽略其余的。学习汇编之所以如此有用,是因为汇编与模拟器应该处理的机器代码进行了 1:1 的转换。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-30
        • 2019-06-16
        • 1970-01-01
        • 2019-01-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多