机器指令翻译成 JavaScript —— No.5 指令变化
上一篇,我们通过内置解释器的方案,解决任意跳转的问题。同时,也提到另一个问题:如果指令发生变化,又该如何应对。
指令自改
如果指令加载到 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 指令变化的更多相关文章
- 【探索】机器指令翻译成 JavaScript
前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...
- 机器指令翻译成 JavaScript —— No.6 深度优化
第一篇 中我们曾提到,JavaScript 最终还得经过浏览器来解析.因此可以把一些优化工作,交给脚本引擎来完成. 现代浏览器的优化能力确实很强,但是,运行时的优化终归是有限的.如果能在事先实现,则可 ...
- 机器指令翻译成 JavaScript —— No.7 过渡语言
上一篇,我们决定使用 LLVM 来优化程序,并打算用 C 作为输入语言.现在我们来研究一下,将 6502 指令转换成 C 的可行性. 跳转支持 翻译成 C 语言,可比 JS 容易多了.因为 C 支持 ...
- 机器指令翻译成 JavaScript —— 终极目标
上一篇,我们顺利将 6502 指令翻译成 C 代码,并演示了一个案例. 现在,我们来完成最后的目标 -- 转换成 JavaScript. 中间码输出 我们之所以选择 C,就是为了使用 LLVM.现在来 ...
- 机器指令翻译成 JavaScript —— No.2 跳转处理
上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」. 跳转指令,分无条件跳转.条件跳转.从另一个角度,也可分: 静态跳转:目标地址已知 动态跳转:目标地址 ...
- 机器指令翻译成 JavaScript —— No.3 流程分割
上一篇 我们讨论了跳转指令,并实现「正跳转」的翻译,但最终困在「负跳转」上.而且,由于线程模型的差异,我们不能 1:1 的翻译,必须对流程进行一些改造. 当初之所以选择翻译,而不是模拟,就是出于性能考 ...
- 机器指令翻译成 JavaScript —— No.4 动态跳转
上一篇,我们用模拟流程的方式,解决了跳转问题. 不过静态跳转,好歹事先是知道来龙去脉的.而动态跳转,只有运行时才知道要去哪.既然流程都是未知的,翻译从何谈起? 动态跳转,平时出现的多吗?非常多!除了 ...
- 四十年前的 6502 CPU 指令翻译成 JS 代码会是怎样
去年折腾的一个东西,之前 blog 里也写过,不过那时边琢磨边写,所以比较杂乱,现在简单完整地讲解一下. 前言 当时看到一本虚拟机相关的书,正好又在想 JS 混淆相关的事,无意中冒出个问题:能不能把某 ...
- [书籍翻译] 《JavaScript并发编程》第一章 JavaScript并发简介
> 本文是我翻译<JavaScript Concurrency>书籍的第一章,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并 ...
随机推荐
- 06.SQLServer性能优化之---数据库级日记监控
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 之前说了一下数据库怎么发邮件:http://www.cnblogs.com/duniti ...
- CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]
上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...
- HTML骨架结构
前面的话 一个完整的HTML文档必须包含3个部分:文档声明.文档头部和文档主体.而正是它们构成了HTML的骨架结构.前面已经分别介绍过文档声明和文档头部,本文将详细介绍构成HTML骨架结构的基础元 ...
- .net 分布式架构之任务调度平台
开源地址:http://git.oschina.net/chejiangyi/Dyd.BaseService.TaskManager .net 任务调度平台 用于.net dll,exe的任务的挂载, ...
- Oracle 数据库知识汇总篇
Oracle 数据库知识汇总篇(更新中..) 1.安装部署篇 2.管理维护篇 3.数据迁移篇 4.故障处理篇 5.性能调优篇 6.SQL PL/SQL篇 7.考试认证篇 8.原理体系篇 9.架构设计篇 ...
- Java列表
Java列表踩过的坑 其中subList是RandomAccessSubList,不是序列化的列表,不可以加入tair. 加入tair测试代码 @Autowired private CacheMana ...
- document.compatMode
在我电脑屏幕上显示的 电脑是 1920*1080这是在document.compatMode:css1Compat模式 window.screen.availWidth 1920 window.scr ...
- 非技术1-学期总结&ending 2016
好久好久没写博客了,感觉动力都不足了--12月只发了一篇博客,好惭愧-- 今天是2016年最后一天,怎么能不写点东西呢!! 学期总结 大学中最关键一年的第一个学期,共4个月.前20天在学网络方面的,当 ...
- 大数据之Yarn——Capacity调度器概念以及配置
试想一下,你现在所在的公司有一个hadoop的集群.但是A项目组经常做一些定时的BI报表,B项目组则经常使用一些软件做一些临时需求.那么他们肯定会遇到同时提交任务的场景,这个时候到底如何分配资源满足这 ...
- CentOS Mono Nginx 部署 MVC4+WebApi
CentOS Mono Nginx 部署 MVC4+WebApi 经过几天的折磨,终于在CentOS上成功部署了MVC4+WebApi.Mono上的服务器推荐两种:Jexus(国产高人写的一款很牛的服 ...