我们知道C51的指令存储在ROM中,它需要从ROM中取出指令才能知道该干什么事。一条指令,首先应该告诉计算机要做什么性质的操作,是加减,还是跳转判断等;其次,还需要给出拿去运算的数据,可以是直接的数据(就是立即能用的数,立即数),也可以是数据存放的地址。那么如何告诉计算机我这个操作码后面跟的是立即数还是地址呢?简单,做个记号,用#来表示立即数,没记号的都是地址。取出指令时,要放在指令寄存器IR里,送到指令译码器ID里进行译码,随后生成相应的控制命令C,这一点是自然而然的,因为计算机本身是要通过硬件执行的,一个指令代码要译码过后才能被解读。不然直接给CPU一个10001000它根本不知道该干什么,通过译码,可能也是生成一些10001000类似的数,但是其对应电平可以直接操作一些硬件,产生相应的动作,在外面的人看来,就是形成了各种不同得控制信号。
这里还需要注意到一件事,就是我取指的时候,程序计数器pc是要+1的,这个加1不是说直接加1,而是说指向下一条指令的意思,它可能就在上一条指令的物理地址的后面,也可以是跳转过的,距离上一条指令很远。都可以,反正就是要指向下一条计算机要运行的指令。那么,这个判断是在什么时候进行呢,具体怎么执行呢?比如MOV类指令,取指后我这个PC物理地址应该加1还是2还是3或者更多?
翻开某本教材的后面的附录:
MOV A,Rn E8H~EFH 字节1 机器周期1
MOV A,direct E5H direct 字节2 机器周期1
MOV A,#data 74H data 字节2 机器周期1
MOV direct2,,direct1 85H direct1,direct2 字节3 机器周期2
MOV DPTR,#data16 90H addr15-8 addr7-0 字节3 机器周期2
MOVX A,@Ri E2H~E3H 字节1 机器周期2 这里侧面显示寄存器间接寻址的只能是R0和R1
MOVX A,@DPTR E0H 字节1 机器周期2
我们看到了,指令系统规定了的字节和机器周期对不同内容的MOV指令是不同的,这也是很合理的。如果可以简单的话,谁不想每条指令都是1个字节一个机器周期呀。因为这是最快的了。然而,天下没这种好事——你既想有不同的指令来包含不同的内容,又想这种指令是那么的简短以至于可以放在一个字节里,或者在一个机器周期里就执行完。
对于译码器而言,他看到了的MOV和我们看到的MOV肯定是不同的。我们就看到了上面每条都是MOV打头,但是他看到的是可能E8H,74H之类的。所以,比如他看到了74H,立马就知道了这是MOV A,#data型的,他肯定也知道了这个指令是有两个字节的,因为需要下一个字节存放操作码,也就是某个立即数。所以,他肯定也告诉了PC需要往后移动两个字节作为下一条指令的地址。这样,我们也能理解了为什么MOV direct2 ,direct1需要3字节(一个操作码85H,两个地址direct1、2正好三个字节来存储),也理解了为啥MOV A, Rn只需要1个字节(因为R0-R7只用8个数就能代表,全体用一个字节来代表绰绰有余)。而对于我们而言,我们只看到MOV的头,就会心生疑惑,不是说取指第一字节就该决定PC加多少了吗?那光看MOV的头也看不出到底该加多少呢。我们有这样的疑惑是因为我们不知道虽然都是MOV,但是不同类型的MOV他们在指令系统里的编码是不同的。计算机确实只要看到第一个字节里的编码就能知道这个MOV是哪种具体的MOV,以及后面还有几个字节和需要的周期。
再来考虑机器周期数目问题,首先能在一个周期里办完的那肯定最好咯。2个以上的机器周期肯定是事务复杂导致的,不过好在除了乘MUL除DIV是4周期,别的都是2周期或更少了。实际上,对于51的指令,字节数和机器周期数的组合只可能是11,12,21,22,32和14.
下图是MCS-51系列单片机的指令时序图:
用这个图再来解释一次,
11组合的比如MOV A,Rn 其操作码E8H~EFH
21组合的比如MOV A,direct 其操作码E5H direct
12组合的比如MOVX A,@Ri其操作码 E2H~E3H
我们发现,可能设计者的初衷就是每个机器周期的S1S4都去读一次操作码或者操作数,然后根据实际情况对这些读到的做处理或者不作处理。比如12组合的读一次就够了(比如E2H就在第一个字节,读一次就行了计算机已经知道了全部内容),而后面的每次读到的都是和第一次一样的,所以判为无效。而对于21组合的来说,S4是需要去读一下操作码的。
这是访问外部程序存储器的相关内容,对应的汇编代码有
MOVC A,@A+DPTR 93H 1字节 2周期
MOVC A,@A+PC 83H 1字节 2周期
很明显由于是对外部ROM的读取,故而没有MOVC @A+PC,A这种写操作。
这里的ALE是地址锁存信号,因为扩展ROM的时候,要用16线去寻址,此时P0口既要做地址的低8位与P2口的高8位组成16位去寻址选中指令单元,又要将选中的指令单元里的内容即具体的指令代码传入CPU中执行相应动作,故而需要有个机制来分时复用。这个机制就是ALE和PSEN,ALE为高时,P0是做地址口用的,上面会出现地址信息,同时PSEN无效,也就是读外部指令是失效的。而ALE从高跳转为低的时候的下降沿,这个时候把刚才P0口的地址锁存在锁存器中,因为接下来的低电平时刻我需要用P0口来传数据。当然,P0口保持地址输出的状态应该比ALE下降沿稍微久一点,确保锁存时刻上面的地址信号是还在的。锁存好地址后,就知道去哪里取指了,将取出的指令内容用P0口传回CPU,自然的,这时候PSEN应该让他有效,允许读数据进来。传好之后,ALE再次变成高电平,这时P0口上又出现了低8位地址,PSEN再次无效,不让数据读进来,一直等下一个下降沿的到来时锁存在锁存器中。
再看这种情况,这是MOVX类型,这种类型不论是采用Ri还是DPTR间接寻址,都只是1字节2周期。
MOVX A,@Ri E2H~E3H 字节1 机器周期2
MOVX A,@DPTR E0H 字节1 机器周期2
对应这两个读操作,还有两个写操作。
MOVX @Ri,A F2H~F3H 字节1 机器周期2
MOVX @DPTR,A F0H 字节1 机器周期2
在读入ROM中的指令后,得知是MOVX指令,CPU得知接下去要操作的RAM中的数据地址,因此P0口将出现对应地址。如果是DPTR类型的,由于他是16位寻址,所以仍然是P2高8位P0低8位的方式。如果是Ri类型,那么只需要用P0做8位地址输出就可以。在ALE下降沿进行锁存。然后在P0口进行数据的读入或者输出。由于这是对外部RAM的读写操作,所以要注意读写线的信号使能。
而且你还能注意到一些区别,之前外部程序存储器PSEN信号是一直在P0口作为数据传入时是有效的。而在MOVX这里,有点差别,他的失效时间会更长,以保证数据传送不被干扰。
上一篇:51单片机PS2键盘解码实验--C51源代码
下一篇:单片机 C51 编程要点总结
推荐阅读最新更新时间:2024-03-16 16:24