JUC-3指令增强
扩充条件转移指令
条件转移指令的硬件扩充
在JUC-3基本模块中已经支持JZ和JNZ指令,现在扩充依据其他3个标志位的条件转移指令JC、JNC、JO、JNO、JS、JNS。分析指令编码表,8条条件转移指令由IR的8、7、6位区分;其中IR8和IR7区分所测试的标志位类型,即区分N、Z、O、C,IR6区分所测试的标志位为1还是为0。因此修改基本版中BM=3依据标志位的微转移地址形成逻辑,在juc3-ch2.adoc#fig-20基础上增加一个4选1多路器,用IR8和IR7控制多路器选择标志位,IR6控制异或门决定是否取反,如图 1。
增强移位指令
在JUC-3基本模块中移位指令只有算术右移SAR和逻辑左移SHL两条,并且移出的数据被丢弃。本节增强移位指令,一方面将移出的数据位放入PSW的CF标志位,以便后续指令使用;另一方面扩充移位指令的种类。
移位指令的硬件扩充
移位操作分逻辑移位、算术移位和循环移位三大类,其中循环移位根据进位位是否一起参加循环,可分为不带进位循环移位和带进位循环移位两种。移位操作如图 2。
从图 2可以看出,除了左移和右移的不同,不同移位操作的区别主要是移入的数据来源不同。如果16位移位数据是d,左移时移入最低位d[0]的数据根据不同的的移位操作可取0、最高位d[15]或PSW中的CF;右移时移入最高位d[15]的数据根据不同的的移位操作可取d[15] 自身、0、最低位d[0]或CF。因此可以用两个多路器选择左移和右移时的移入数据,如图 3。
图中多路器的选择信号ShiftType连接指令寄存器IR的8、7两位,从指令编码表可以看出,当IR8-7分别为00、01、10、11时,对应的移位指令分别是:算术移位、逻辑移位、循环移位和带进位的循环移位。
移出位送入PSW的CF标志位
从运算器设计已经知道,PSW保存ALU的运算结果特征标志,其中CF是加法运算的进位,现在要使CF也可以来源于移位寄存器的移位输出,左移时将X的最高位送CF,右移时将X的最低位送CF。因此可以用一个多路器选择CF的来源,选择逻辑如图 4,SL有效时,选择输入数据的X[15]送入CF;SR有效时,选择输入数据的X[0]送入CF;SL和SR同时无效时(不移位),选择加法产生的进位送入CF;SL和SR不应该出现同时有效的情况,如果有这种情况出现,也选择加法产生的进位送入CF。
实战:移位指令的微程序设计与调试
从上面的硬件设计可以看出,不同移位指令移入数据来源的选择由硬件实现,移出数据位送到PSW的CF标志位也是由硬件实现。所以各个移位指令的微程序是相同的,但是微程序入口地址不同,所以只要在相应的微地址填入左移或右移的微程序。
(1)用以下调机程序验证右移指令的微程序。
MOV #0001H,R0
SHR R0
JC FFFDH(PC)
HALT
移位指令将移出的位保存在PSW的CF标志位中,所以可以用JC指令判断移出位的值。第3行指令中的“FFFDH(PC)”表示相对寻址,其中“FFFDH”是补码表示的偏移量,即十进制“-3”。
分析上述程序的功能,运行之后相关寄存器和PSW会有怎样的变化,第一次移位后JC指令是否转移,第二次呢?转移的目的地址是多少。
(2)用以下程序验证循环左移指令的微程序。
ORG 0030H
MOV #0505H,R1
TEST #0001H,R1
JZ 3(PC)
ROL R1
JMP 0032H
HALT
分析程序的功能,运行之后相关寄存器和PSW会有怎样的变化,程序是否转移,转移的目的地址是多少。
支持堆栈及相关指令
数据通路和微命令的扩展
堆栈是主存储器中的一块连续的专用存储区域,它只能从一端存入或取出数据,遵循后进先出(LIFO)的规则。如果是从低地址一端操作,随着存入堆栈数据的增加,存放数据的单元地址减小,通常称作堆栈向上增长;如果是从高地址一端操作,随着存入堆栈数据的增加,存放数据的单元地址增大,通常称作堆栈向下增长。JUC-3的堆栈是向上增长的,堆栈的存储空间为002FH~0008H。
堆栈操作必须通过堆栈指示器SP,它是CPU中的一个专用寄存器,用来指向栈顶元素。将数据压入堆栈时,首先将SP的内容减1,使SP指向一个新的内存单元,然后将数据存入以SP内容为地址的内存单元;将数据从堆栈中取出时,首先以SP内容为地址取出该内存单元的数据,然后将SP的内容加1,使SP指向新的栈顶。总之,SP始终指向当前的栈顶元素。增加了SP寄存器的JUC-3E模型机结构如图 5。SP的初始值为0030H。增加了SPoe和SPce微命令的微指令编码见表 1。
| F0:XXoe (3位) |
F1:XXce (3位) |
F2:ALU (4位) |
F3:PSW (3位) |
F4:S/D (1位) |
F5:SB (2位) |
F6:PC (1位) |
F7:Mem (3位) |
F8:BM (3位) |
F9: NA (9位) |
|---|---|---|---|---|---|---|---|---|---|
0:NOP |
0:NOP |
由ALU |
0:NOP |
0:DST |
0:NOP |
0:NOP |
0:NOP |
||
1:PCoe |
1:PCce |
的硬件设 |
1:PSWce |
1:SRC |
1:ARce |
1: PCinc |
1:RD |
||
2:GRSoe |
2:GRSce |
计决定 |
2:DRces |
2:WR |
|||||
3:RFoe |
3:IRce |
3:DRce |
|||||||
4:RYoe |
4:RYce |
||||||||
5:ARoe |
5:RXce |
||||||||
6:DRoe |
6:RFce |
||||||||
7:SPoe |
7:SPce |
堆栈相关指令的功能和操作
和堆栈操作有关的指令主要有压栈指令PUSH、出栈指令POP、子程序调用指令CALL、子程序返回指令RET。
“PUSH dst”是单操作数指令,但本质上是双操作数的传送,相当于“MOV dst, - (SP)”,其中由SP指向的堆栈单元是隐含操作数,dst的本质是源,但是作为单操作数指令,只有取目的操作数阶段。在取目的操作数的微程序结束时,dst已经存放到RX暂存器中,也就是要放入堆栈的数据。因此在PUSH指令的执行阶段,要将RX暂存器中的“目的操作数”送到堆栈中去。
出栈指令“POP dst” 相当于“MOV (SP)+, dst”,也就是将栈顶单元的内容送给dst。dst可能在主存或寄存器,如果在主存中,其地址已经在取操作数阶段存放在AR中。但是在从堆栈中取出数据时,需要将SP的内容送给AR,这就破坏了AR中的目的地址;所以需要在此之前先将AR的内容保存到RY寄存器。此外栈顶单元的内容取出后还要将SP加1,使SP始终指向栈顶单元。
子程序调用指令(CALL)的功能是使程序转向目的地址,这一点和JMP转移指令是一样的,只要将AR的内容送给PC就可以了;不同的是CALL指令还要为子程序返回指令(RET)做好准备,将下一条指令的地址也就是当前PC的内容压入堆栈。而RET指令所要做的就是将栈顶单元内容取出装入PC中,使程序返回调用处继续执行。
实战:堆栈相关指令的微程序设计与调试
(1)PUSH和POP指令的微程序设计与调试。
用下面的调机程序验证PUSH和POP的微程序。观察堆栈指针SP、堆栈存储单元以及相关寄存器和内存单元的变化,理解堆栈的用法。
ORG 0030H
MOV #0041H,R0
PUSH R0 ;将R0寄存器内容压入堆栈
PUSH 0040H ;将R0寄存器内容压入堆栈
POP (R0) ;将当前栈顶内容存入主存0041H单元
POP R1 ;将当前栈顶内容存入R1寄存器
(2)编写CALL指令的微程序,并设计调机程序验证。
(3)编写RET指令的微程序,并设计调机程序验证。
注意观察子程序返回是否返回到正确的地址,以及返回后堆栈指针的变化。