关于GB/GBC远程调用程序的示例

  • 首先,在了解GBC设计之后,在普通的卡带芯片下,HOMEBANK固定地址0000-3FFF,不可切换,

    且大部分游戏都比较缺少空白的HOMEBANK位置,因此,大部分时候,就需要用到一种方法,就是远程调用。

    也就是说在当前BANK的位置上远程调用其他BANK的内容,然后回到原程序的对应位置上。譬如说在BANK 10:5230的位置上调用BANK:20:6540的程序。

    远程调用程序的原理,实际上就是在调用这个远程程序的时候读取位置上的某些信息(目标的地址已经BANK号),然后把当前位置已经BANK号堆放在栈里面,

    等调用完之后返回的时候,写回当前BANK的位置上。但是在运行远程调用程序的前后,A BC DE HL的数值不能改变。

    首先,在HOMEBANK的某一处地方写下远程调用的程序。

    822-2017-09-20-083640-png

    然后,在调用这个程序的时候,后面写上必要的信息。

    825-2017-09-20-085214-png

    这里的CALL 0180后面三个字节的信息,就是需要远程目标的位置。并不是程序。

    首先,CALL的原理就是将当前位置PC+3压入栈,然后当运行到RET之后,就返回到弹出栈的位置上。

    那么现在开始分析远程调用的程序。

    826-2017-09-20-085254-jpg

    首先CALL之后会压入5233的位置到栈。

    然后再给栈偏移一个数值,将必要的数据(原BANK号,已经位置信息),保存在栈的中间,

    因为这里的压入弹出栈的数据都只作一个临时存放,所以就要放到重要信息后面。

    827-2017-09-20-090425-jpg

    那么,现在就开始整理一系列的数据。

    首先就是要把原地址5233再+3,因为刚才在CALL远程程序的时候有三个字节不是程序的,所以返回的时候就需要跳过这三个字节。

    828-2017-09-20-090942-jpg

    那么首先将栈偏移一个数值载入到HL寄存器,读取数值+3之后写回去。

    顺便要把这个数值5233载入到寄存器里面。因为还要读取这个地址后面的远程目标信息。

    830-2017-09-20-091508-jpg

    5233成功转变成5236。

    然后载入栈+一个偏移的数值,让HL寄存器定位回到刚才隔空的位置上。

    然后读取5236上的目标地址数值写入到栈空白位置上。

    为什么要写到栈?因为当运行到RET之后,原理就是程序恢复到弹出这个栈的数值地址上。

    831-2017-09-20-092433-jpg

    目标地址6540成功写到栈位置上。

    接下来就要,写入一个对应的数值,让调用完毕之后返回到HOMEBANK一个程序地址上,让这个程序切换回原来BANK号已经地址。

    832-2017-09-20-092804-png

    833-2017-09-20-092838-png

    将01AB程序的地址,写到栈。

    然后再将当前BANK号写入到栈。

    834-2017-09-20-093121-png

    由于每个游戏设计都不同,有些游戏是用一个地址来保存当前BANK号,一般是存放在HRAM的某个地址上。

    有些就是在每个BANK的第一个字节上记录着BANK号。这个展示的就是这种每个BANK记录着BANK号信息的。

    那么最后一步就是切换目标BANK了。相继弹出恢复刚才压入的三个寄存器上的数值。

  • 836-2017-09-20-094019-png

    最后,当程序将要运行01AA:RET时候,观察栈对应的位置。就是指向目标地址。

    837-2017-09-20-094239-png

    到这里,证明已经可以成功远程到BANK20:6540地址上的位置了。而且栈的位置也刚好在CFFB上,也就是01AB上面。

    那么只要当程序运行到RET指令,就会返回到01AB的程序上。继续执行一系列后续操作。返回到原位置上。

    838-2017-09-20-094736-png

    然后写下压入弹出栈操作指令观察,是否会破坏返回必要用到的重要信息。

    运行之后发现,在压入栈之后,只会覆盖掉一些没用的临时数据,事实证明,远程程序是成功了。

    839-2017-09-20-095113-png

    那么现在就继续运行到RET看是否能回到01AB的位置上。

    842-2017-09-20-095405-png

    然后现在,只需要把存放在栈里面的BANK号取出来,然后就可以成功切换回原来的地址上了。

    方法还是那样把栈+一个偏移的位置载入到寄存器上,然后读取出来,切换BANK,最终栈的寄存器数值调整到需要弹出返回到原地址的目标上即可。

    843-2017-09-20-095944-png

    成功回到原地址上,远程调用完成。

    844-2017-09-20-100325-png

Join us

Have your own thoughts on this discussion? Wanna help others, avoid the mistakes you met before? Wanna contribute more to this or other topic? Just join us! Registration is free. Join us!