上一篇,我们通过内置解释器的方案,解决任意跳转的问题。同时,也提到另一个问题:如果指令发生变化,又该如何应对。

指令自改

如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的。然而,对应的 JS 是事先翻译好的,已经不能改了。如果运行时突然变卦,那相应的 JS 就作废了 —— 如果修改的是跳转指令,甚至会影响已划分的流程。所以为了保守起见,指令被改后进入模拟状态。

因此,我们得监控指令区的修改:

function store(addr, val) {
// 修改指令区
if (0x0600 <= addr && addr <= ...) {
...
}
MEM[addr] = val
}

将存储操作封装成函数,这样就可在写入时做一些判断。如果修改了指令区的数据,则进入解释模式(甚至永远保持解释模式)。

当然,还可以做一个 JIT 引擎,在运行时翻译。不过很复杂,这里就不考虑了。

对存储进行封装,这也是有必要的。之前为了简化问题,将整个地址空间都当做内存,其实是不严谨的。事实上,内存只是地址空间的一部分而已。其他还有屏幕、键盘,以及各种 ABI,都是通过地址交互的。

所以,读写最终都需要一层封装:

function store(addr, val) {
...
MEM[addr] = val;
} function load(addr) {
...
return MEM[addr];
}

指令变化

如果不修改指令数据,指令是否也会变化?听起来有些匪夷所思。不过,在那个系统资源极度匮乏的年代,总会有些神奇的东西。

我们在第一篇中提到,地址总线是 16 位,最多只能访问 64K 的空间。这是否意味着,程序最大只能做到 64K?

回顾一下,小时候玩的红白机游戏(当然,那时都用卡带,也看不出游戏有多大)。后来有电脑模拟器,就可以看到 NES 文件的大小了。

事实上超过 64K 的多得是,有些「大型游戏」甚至有好几百 K,例如:

光靠 16 位的地址,是如何访问的?为此,前辈们发明了一种叫 Mapper 的黑科技。它内置在游戏卡带芯片里,对 CPU 是透明的。

Mapper 的种类五花八门,但基本思路差不多:用某些特殊地址,来扩展寻址能力。

假设 0x0000 ~ 0x0fff 空间是给卡带的。若把 0x0fff 这个特殊地址设置成 1,这时访问 0x0005,实际访问到的物理位置是 1 * N + 5;如果设置的是 2,再访问 0x0005,对应的物理位置则是 2 * N + 5。这样,就可突破 64K 的限制了。

相当于把特殊地址,当做类似段寄存器的功能。只不过这是卡带自己搞的一套内部方案,CPU 是毫不知情的。

当然,实际情况比这复杂得多。本系列我们讨论的仅仅是指令翻译,并非要实现一个 NES 环境,所以就不考虑了。

结尾

关于 6502 指令翻译成 JavaScript 的可行性分析,就到此为止。

我们之所以要翻译,而不是纯粹模拟,就是为了尝试追求最高效率。不过,就目前的翻译过程来看,仍存在很多可优化的地方。

下一篇,我们尝试利用现有工具,对逻辑进行深度优化。

机器指令翻译成 JavaScript —— No.5 指令变化的更多相关文章

  1. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  2. 机器指令翻译成 JavaScript —— No.6 深度优化

    第一篇 中我们曾提到,JavaScript 最终还得经过浏览器来解析.因此可以把一些优化工作,交给脚本引擎来完成. 现代浏览器的优化能力确实很强,但是,运行时的优化终归是有限的.如果能在事先实现,则可 ...

  3. 机器指令翻译成 JavaScript —— No.7 过渡语言

    上一篇,我们决定使用 LLVM 来优化程序,并打算用 C 作为输入语言.现在我们来研究一下,将 6502 指令转换成 C 的可行性. 跳转支持 翻译成 C 语言,可比 JS 容易多了.因为 C 支持 ...

  4. 机器指令翻译成 JavaScript —— 终极目标

    上一篇,我们顺利将 6502 指令翻译成 C 代码,并演示了一个案例. 现在,我们来完成最后的目标 -- 转换成 JavaScript. 中间码输出 我们之所以选择 C,就是为了使用 LLVM.现在来 ...

  5. 机器指令翻译成 JavaScript —— No.2 跳转处理

    上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」. 跳转指令,分无条件跳转.条件跳转.从另一个角度,也可分: 静态跳转:目标地址已知 动态跳转:目标地址 ...

  6. 机器指令翻译成 JavaScript —— No.3 流程分割

    上一篇 我们讨论了跳转指令,并实现「正跳转」的翻译,但最终困在「负跳转」上.而且,由于线程模型的差异,我们不能 1:1 的翻译,必须对流程进行一些改造. 当初之所以选择翻译,而不是模拟,就是出于性能考 ...

  7. 机器指令翻译成 JavaScript —— No.4 动态跳转

    上一篇,我们用模拟流程的方式,解决了跳转问题. 不过静态跳转,好歹事先是知道来龙去脉的.而动态跳转,只有运行时才知道要去哪.既然流程都是未知的,翻译从何谈起? 动态跳转,平时出现的多吗?非常多!除了 ...

  8. 四十年前的 6502 CPU 指令翻译成 JS 代码会是怎样

    去年折腾的一个东西,之前 blog 里也写过,不过那时边琢磨边写,所以比较杂乱,现在简单完整地讲解一下. 前言 当时看到一本虚拟机相关的书,正好又在想 JS 混淆相关的事,无意中冒出个问题:能不能把某 ...

  9. [书籍翻译] 《JavaScript并发编程》第一章 JavaScript并发简介

    > 本文是我翻译<JavaScript Concurrency>书籍的第一章,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并 ...

随机推荐

  1. boost强分类器的实现

    boost.cpp文件下: bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator, int _numSampl ...

  2. 深究标准IO的缓存

    前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...

  3. vscode 1.5安装体验

    1.下载安装 官方下载地址: http://code.visualstudio.com/ 界面截图: 2.图标显示功能File Icon Themes vscode1.5版本文件夹视图,可显示文件类型 ...

  4. android 事件分发机制详解(OnTouchListener,OnClick)

    昨天做东西做到触摸事件冲突,以前也经常碰到事件冲突,想到要研究一下Android的事件冲突机制,于是从昨天开始到今天整整一天时间都要了解这方面的知识,这才懂了安卓的触摸和点击事件的机制.探究如下: 首 ...

  5. 深入理解javascript函数定义与函数作用域

    最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把思路整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径 ...

  6. SAP CRM 显示消息/在消息中进行导航

    向用户展示消息,在任何软件中都是十分重要的. 在SAP CRM WEB UI中展示消息,不是一项很难的任务,只需要创建消息并在之后调用方法来显示它 消息类和消息号: 我在SE91中创建了如下的消息类和 ...

  7. 微信小程序二维码推广统计

    微信小程序可以通过生成带参数的二维码,那么这个参数是可以通过APP的页面进行监控的 这样就可以统计每个二维码的推广效果. 今天由好推二维码推出的小程序统计工具HotApp小程序统计也推出了带参数二维码 ...

  8. LINQ to SQL语句(7)之Exists/In/Any/All/Contains

    适用场景:用于判断集合中元素,进一步缩小范围. Any 说明:用于判断集合中是否有元素满足某一条件:不延迟.(若条件为空,则集合只要不为空就返回True,否则为False).有2种形式,分别为简单形式 ...

  9. How to accept Track changes in Microsoft Word 2010?

    "Track changes" is wonderful and remarkable tool of Microsoft Word 2010. The feature allow ...

  10. Handler

    1.1 继承AbstractController优点:能定制请求方式 package cn.happyl.controller; import javax.servlet.http.HttpServl ...