- 注册时间
- 2004-9-4
- 最后登录
- 1970-1-1
|
我打算为NCTOOLS增加TRACE功能,苦于实现起来比较麻烦,希望大家能帮忙考虑一下如何实现比较好,以及其它的一些你能想到的问题和要注意的东西.
目前我想了三种方案:
========
方案一
========
今天上午刚学习了8086/8088系统中断的工作机理,也对比了一下文曲星的CPU.由于8086/8088CPU在硬件设计时PSW寄存器中设计了TF标志位,所以它实现DEBUG中的TRACE功能相对来说要容易得多.但6502的CPU却不行了,硬件上无法产生单步中断,因此只好使用软件模拟单步中断服务.
我大体想了一下,要是使用软件模拟单步执行服务的话,要做到以下几点:
1.判断是否启用单步执行.若是则执行一些功能,如果不是则直接返回.
2.在单步中断服务程序执行时必须保证不再处于单步状态.否则的话....
3.单步执行中断服务必须在每执行一条指令后都能有效地发挥作用,也就是说,必须真正做到 "单"步.这个要精确地控制在"本条指令执行后,下一条指令读取之前".这样的话,必须在每执行完一条执令后有一个中断,使CPU转向单步执行服务程序.这样的话会大大影响文曲星的运行速度.
这三点不是太容易实现.因为仅仅第二个就足以让人大伤脑筋,更不用说第三个了.
想来想去,觉得把单步执行中断服务放在系统的IRQ中比较好.因为这样的话,系统一旦进入IRQ,就不会再响应同等级的中断,也就不会再响应单步中断了.这样可以解决第二个问题了.只是不知道IRQ在多少时间内会产生一次,能不能抓住每一条指令.假如两次IRQ发生的时间差一定小于CPU运行两条指令的时间差,那么这种方案可行.这样的话,单步中断服务程序的主要任务有下面几个:
1.禁用IRQ.这个已经在进入服务程序时实现了.
2.判断是否处于TRACE状态,若否,则返回.
3.输出上条指令执行后CPU的各寄存器的值,放于指定位置.
4.返回.
========
方案二
========
直接使用子程序,什么时候需要单步,就直接调用子程序来完成单步执行一条指令.
这样的话,需要有下面的功能:
给定CPU的初值和下一条指令的地址后,能准确地提取下一条指令的操作码和操作数,能有效地控制CPU只执行这么一条指令并准确地记录执行完这么一条指令后CPU各寄存器的状态.
子程序大约有下面的结构:
程序功能: 单步执行一条指令
入口参数: 下一条指令所在地址(PC值);下一条指令执行前的 A,X,Y,P,S 的值;执行后CPU各寄存器的值要放的位置.
出口参数: 入口参数中给定位置的指令执行后, PC,A,X,Y,P,S 的值.
运行过程:
A.获取PC,置于伪PC.
B.读取指令的操作码,发送到 临时指令缓存区; 伪PC要加一.
C.根据指令的操作码,读取操作数,发送到 临时指令缓存区; 伪PC适当地增加或者不变; 生成 临时指令缓存区中的返回指令.
D.保护现场,并将提供的 A,X,Y,P 的值读入CPU相应的寄存器.
E.调用缓冲区程序.
F.记录 A,X,Y,P 的值,写入指定位置; 根据情况计算PC和S的值,并记录于指定位置.
G.恢复现场
H.返回.
这样的话,可以实现单步执行的模拟.缺点是:
1.在主程序中要写调用单步的代码,而且要求提供的入口参数较多;
2.如果遇到与堆栈相关的操作,必须想办法处理原程序与本段程序的堆栈使用冲突,有些还要考虑程序对PC的影响.这些操作包括: PHA,PLA;PHP,PLP;JSR,RTS;INT,RTI.
========
方案三
========
完全模拟CPU的运作
这种方法可以很好地解决方案二中的第二个缺点中提到的问题.只是整体实现起来很麻烦,因为要重新创建堆栈区,以及其它的一些存储区.然后完全模拟CPU的工作,一条指令一条指令地执行,每执行一条就相应地处理这些存储区域.这种方法很笨,很慢,而且想起来很乱.
不知道大家有没有其他的好的方法,希望能共同探讨一下
|
|