机器指令翻译成 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并 ...
随机推荐
- 【原】nodejs全局安装和本地安装的区别
来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...
- java: web应用中不经意的内存泄露
前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
- solr_架构案例【京东站内搜索】(附程序源代码)
注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的. 一:solr服务的端口号.我这里的sol ...
- 【接口开发】浅谈 SOAP Webserver 与 Restful Webserver 区别
接口,强大,简单,交互,跨越平台 下面简单阐述这两大接口思想 一 REST: REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
- .NET Core的日志[5]:利用TraceSource写日志
从微软推出第一个版本的.NET Framework的时候,就在“System.Diagnostics”命名空间中提供了Debug和Trace两个类帮助我们完成针对调试和跟踪信息的日志记录.在.NET ...
- javascript数组查重方法总结
文章参考地址:http://blog.csdn.net/chengxuyuan20100425/article/details/8497277 题目 对下列数组去重: var arr = ['aa', ...
- Effective前端2:优化html标签
div { float: left; } .keyboard > div + div { margin-left: 8px; } --> div{display:table-cell;ve ...
- JDBC简介
jdbc连接数据库的四个对象 DriverManager 驱动类 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 ...
- BPM配置故事之案例1-配置简单流程
某天,Boss找到了信息部工程师小明. Boss:咱们新上了H3 BPM,你研究研究把现在的采购申请流程加上去吧,这是采购申请单. 小明:好嘞 采购申请单 小明回去后拿着表单想了想,开始着手配置. 他 ...