zoukankan      html  css  js  c++  java
  • 【SMB源码解析系列】——001.JumpEngine函数

    在SMB的源码中大概有不到20处看起来很奇怪的指令,它的格式是通过jsr指令调用一个名为JumpEngine的函数,其后并不是跟随某些后续的逻辑指令,而是通过.dw定义了一系列16位地址。

    我们可以看到在jsr指令之前,还会将某个值写入A寄存器。

    JumpEngine函数本身代码并不长:

    让我们来看看这段函数到底做了什么:

    1.将A寄存器的值乘以2,然后写入Y寄存器;

    2.从栈中取出2字节数据,分别写入$04、$05,然后将Y寄存器的值+1;

    3.通过"后索引间接寻址"方式,将($04),y中的数据写入到$06中,又将($04),y+1处的数据写入$07中;

    4.通过"间接寻址"方式,跳转至($0006)处执行代码。

    原本我们如果在966行处调用了jsr指令(此时会先将指令所在地址$8234+2=$8236推入栈中),按正常流程应该在跳转至JumpEngine之后某处调用一次rts指令(把栈中的$8236取出并+1得到$8237),然后程序会跳转至$8237处继续执行。

    但在第二步,我们将栈中的信息手动取出($8236),存入了$04、$05,并将Y寄存器+1,如果OperMode_Task的值是0的话,此时$04、$05中保存的值是$8236,Y寄存器的值为0*2+1=1,lda ($04),y就相当于是把$8236+1=$8237处的数据取出来写入$06,接着又将($04),y+1也就是$8238处的值取出来,写入$07。

    这时我们就发现,968行通过.dw定义的16位地址InitializeGame已经被写入$06、$07中了。

    最后通过唯一的一个间接寻址指令jmp ($0006)我们就跳转到了InitializeGame继续执行代码。

    程序中的其他地方,可能会修改OperMode_Task的值为1,这样第二步Y寄存器的值最终为1*2+1=3,第三步就是把$8239,$8240处的值(ScreenRoutines)取出来了。目前看来这种方式最长可以通过.dw定义100多个函数地址~

    SMB中就是依靠JumpEngine函数,让程序按照某个顺序逐一执行,序列化的完成了整个游戏逻辑的控制。不过我觉得这更像是在射击CPU硬件逻辑时就设计好的一个"语法糖",因为这个函数的思路和指令的实现逻辑结合的实在是太完美无缺了,当然这只是我的个人臆想罢了。

    在时间的巨兽面前,我们只有卑微与无奈的成长
  • 相关阅读:
    数组splice用法
    opacity 适配Ie
    直接贴页面,页面衔接处总会有一像素的间隔
    <script src='url'</script>显示问题
    弹出层
    CF789A. Anastasia and pebbles
    CF789C. Functions again
    HDU2161 Primes
    UVA11752 The Super Powers
    UVA11827 Maximum GCD
  • 原文地址:https://www.cnblogs.com/rebeldancer/p/11674906.html
Copyright © 2011-2022 走看看