差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
oc8051软核 [2018/09/12 10:05]
group003 [4 多路复用器]
oc8051软核 [2018/09/12 17:47] (当前版本)
group003 [参考来源]
行 30: 行 30:
 {{::​oc8051-接口.gif?​380|}} {{::​oc8051-接口.gif?​380|}}
 {{::​oc8051-接口描述.gif.png|}} \\ {{::​oc8051-接口描述.gif.png|}} \\
-====2 模块描述==== +=====2 模块描述===== 
-===2.1 ​oc8051_top===+===2.1 ​译码和运算模块=== 
 +==2.1.1 oc8051_top==
 Ports: Ports:
   * -rst                  reset   * -rst                  reset
行 53: 行 54:
   * -txd      transmit   * -txd      transmit
   * -t0, t1   t/c external inputs   * -t0, t1   t/c external inputs
-===2.2 oc8051_decoder===+==2.1.2 oc8051_decoder==
 oc8051_decoder是主要模块。 该模块从程序存储器中获取操作代码,然后设置控制信号。 \\ oc8051_decoder是主要模块。 该模块从程序存储器中获取操作代码,然后设置控制信号。 \\
 模块有两个内部信号。 \\ 模块有两个内部信号。 \\
行 86: 行 87:
 - rmw          (out) 读-修改-写 指令时有效[oc8051_ports.rmw]\\ - rmw          (out) 读-修改-写 指令时有效[oc8051_ports.rmw]\\
 - pc_wait ​    ​(out)\\ - pc_wait ​    ​(out)\\
-===2.3 oc8051_alu===+==2.1.3 oc8051_alu==
 模块oc8051_alu表示用于算术和逻辑运算的组合逻辑。\\ 模块oc8051_alu表示用于算术和逻辑运算的组合逻辑。\\
 模块有3个8位输入操作数(第三个操作数用于计算PC或DPTR的地址)和3个输入信号。 这三个信号分别是进位,辅助进位和用于位寻址指令的信号。还有四位宽的操作码输入。\\ 模块有3个8位输入操作数(第三个操作数用于计算PC或DPTR的地址)和3个输入信号。 这三个信号分别是进位,辅助进位和用于位寻址指令的信号。还有四位宽的操作码输入。\\
行 107: 行 108:
   * OC8051_ALU_XCH – 交换,第一个输入传输到第二个输出,反之亦然。 如果设置了进位,​则只更改字节的最低半部分   * OC8051_ALU_XCH – 交换,第一个输入传输到第二个输出,反之亦然。 如果设置了进位,​则只更改字节的最低半部分
 运算码在文件oc8051_defines.v中。输出是2个八位宽结果,还有进位,辅助进位和溢出。乘法和除法子模块分别定义在oc8051_multiply 和 oc8051_divide 中。它俩都有八位宽的输入总线和2个八位宽输出总线,1个总线输出结果,另一个总线输出进位标志。 运算码在文件oc8051_defines.v中。输出是2个八位宽结果,还有进位,辅助进位和溢出。乘法和除法子模块分别定义在oc8051_multiply 和 oc8051_divide 中。它俩都有八位宽的输入总线和2个八位宽输出总线,1个总线输出结果,另一个总线输出进位标志。
-===2.4 oc8051_pc===+==2.1.4 oc8051_pc==
 模块oc8051_pc实际上是一个程序计数器。 它计算下一条指令的地址值。模块中的输入是操作码,我们用它来计算地址的值。 还有一些输入用于跳转(op2和op3用于绝对跳转,alu输入用于相对寻址),还有用于选择新pc源的信号(pc_wr_sel)和输入新地址的信号(wr)。 模块oc8051_pc实际上是一个程序计数器。 它计算下一条指令的地址值。模块中的输入是操作码,我们用它来计算地址的值。 还有一些输入用于跳转(op2和op3用于绝对跳转,alu输入用于相对寻址),还有用于选择新pc源的信号(pc_wr_sel)和输入新地址的信号(wr)。
 模块的唯一输出是程序计数器的16位宽的当前值。 模块的唯一输出是程序计数器的16位宽的当前值。
-===2.5 oc8051_rom===+==2.1.5 oc8051_rom==
 该模块包含了程序存储器。 程序存储器取决于我们的实现方式。\\ 该模块包含了程序存储器。 程序存储器取决于我们的实现方式。\\
 模块中的输入是16位地址。 输出是三个8位数据总线和ea_int信号。 输入地址来自数据的第一个字节(data1),第二个和第三个字节(data2,data3)位于以下地址。 这是流水线不间断运行的必备条件。Ea_int信号等于外部ea信号,如果所使用的地址对于内部程序存储器来说太大了,那么就需要使能该信号,来访问外部程序存储器。\\ 模块中的输入是16位地址。 输出是三个8位数据总线和ea_int信号。 输入地址来自数据的第一个字节(data1),第二个和第三个字节(data2,data3)位于以下地址。 这是流水线不间断运行的必备条件。Ea_int信号等于外部ea信号,如果所使用的地址对于内部程序存储器来说太大了,那么就需要使能该信号,来访问外部程序存储器。\\
-===2.6 oc8051_comp===+==2.1.6 oc8051_comp==
 模块oc8051_comp的功能是比较两个输入并在输入相同时设置输出。 在条件跳转时,计算条件需要该模块。\\ 模块oc8051_comp的功能是比较两个输入并在输入相同时设置输出。 在条件跳转时,计算条件需要该模块。\\
 比较输入有不同的选项:\\ 比较输入有不同的选项:\\
行 121: 行 122:
 - 位进位(来自存储器) \\ - 位进位(来自存储器) \\
 这些选项足以满足8051中的所有条件跳转。输出连接到oc8051_decoder的输入,在需要时传输到pc_wr。\\ 这些选项足以满足8051中的所有条件跳转。输出连接到oc8051_decoder的输入,在需要时传输到pc_wr。\\
-===2.7 oc8051_op_select===+==2.1.7 oc8051_op_select==
 所有来自程序存储器的数据都要经过该模块。它有三项任务。\\ 所有来自程序存储器的数据都要经过该模块。它有三项任务。\\
 第一项任务是选择使用哪种内存,内部或外部。这项任务有点像多路复用器:它具有用于输入的ea和ea_int信号(当这两个信号任意一个低电位时,将是外部空间的读周期)和输出。\\ 第一项任务是选择使用哪种内存,内部或外部。这项任务有点像多路复用器:它具有用于输入的ea和ea_int信号(当这两个信号任意一个低电位时,将是外部空间的读周期)和输出。\\
 该模块的第二个任务是接收中断。为此,除了3个8位输入之外,该模块还具有两个用于接收中断的输入信号。这些是信号int和8位的int_v。如果设置了int信号,我们有一个中断,在8位总线上,我们接收到中断程序的地址(高8位为零)。在中断时,检查当前正在执行的指令是否大于一个时钟周期(输入信号rd),然后将LCALL操作码发送到第一个输出。随后发送中断程序其他两个输出的地址。\\  该模块的第二个任务是接收中断。为此,除了3个8位输入之外,该模块还具有两个用于接收中断的输入信号。这些是信号int和8位的int_v。如果设置了int信号,我们有一个中断,在8位总线上,我们接收到中断程序的地址(高8位为零)。在中断时,检查当前正在执行的指令是否大于一个时钟周期(输入信号rd),然后将LCALL操作码发送到第一个输出。随后发送中断程序其他两个输出的地址。\\
 该模块的最后一个任务是检查操作码并发送存储器地址,以便将结果写入输出中。这与需要DPTR用于计算结果的指令和使用B寄存器的指令一起使用。使用此选项可以实现以后的立即寻址模式。必须要小心啦,因为第二个操作数有两个不同输出,一个用于ALU中的立即操作数,另一个用于直接寻址。\\ 该模块的最后一个任务是检查操作码并发送存储器地址,以便将结果写入输出中。这与需要DPTR用于计算结果的指令和使用B寄存器的指令一起使用。使用此选项可以实现以后的立即寻址模式。必须要小心啦,因为第二个操作数有两个不同输出,一个用于ALU中的立即操作数,另一个用于直接寻址。\\
-===2.8 oc8051_regX===+==2.1.8 oc8051_regX==
 oc8051_regX模块代表X位寄存器,其功能仅在于将信号延迟一个时钟周期。 除了时钟和复位输入外,它们还具有数据输入和输出。 oc8051_regX模块代表X位寄存器,其功能仅在于将信号延迟一个时钟周期。 除了时钟和复位输入外,它们还具有数据输入和输出。
-====3 数据存储器和特殊功能寄存器(SFR)====+===2.2 数据存储器和特殊功能寄存器(SFR)===
 下面的模块包括两部分, 下面的模块包括两部分,
   * 数据存储器和特殊功能寄存器模块   * 数据存储器和特殊功能寄存器模块
行 147: 行 148:
 地址可以不同,以便处理位操作指令或字节操作指令。物理地址定义在oc8051_defines.v文件中。\\ 地址可以不同,以便处理位操作指令或字节操作指令。物理地址定义在oc8051_defines.v文件中。\\
 除了输入空间外,还有数据地址输入空间和数据输出空间。\\ 除了输入空间外,还有数据地址输入空间和数据输出空间。\\
-===3.1 oc8051_ram_top===+==2.2.1 oc8051_ram_top==
 该模块包含数据存储器。 它的工作方式类似于普通内存和我们所需的(能够进行位寻址)的内存类型。 在位寻址模式中,我们必须使用地址字节中正确的位数值。 当写周期时,必须读取整个字节,改变相应位的值,必须将所有字节再写回存储器。\\ 该模块包含数据存储器。 它的工作方式类似于普通内存和我们所需的(能够进行位寻址)的内存类型。 在位寻址模式中,我们必须使用地址字节中正确的位数值。 当写周期时,必须读取整个字节,改变相应位的值,必须将所有字节再写回存储器。\\
 该模块的子模块是oc8051_ram。 该模块依赖于所用的实现方式,它是一个具有8位地址的普通存储器。 由于流水线的原因,需要同时进行读写。\\ 该模块的子模块是oc8051_ram。 该模块依赖于所用的实现方式,它是一个具有8位地址的普通存储器。 由于流水线的原因,需要同时进行读写。\\
-===3.2 oc8051_acc===+==2.2.2 oc8051_acc==
 最常用的SFR是累加器(ACC)。 除了标准端口之外,它还有8位宽的输入,用于给第二个ALU结果(data2_in)。还有一个信号wad2,当第二结果写入寄存器时,该信号被激活。 还有另一个输出,用于奇偶校验(p)。 最常用的SFR是累加器(ACC)。 除了标准端口之外,它还有8位宽的输入,用于给第二个ALU结果(data2_in)。还有一个信号wad2,当第二结果写入寄存器时,该信号被激活。 还有另一个输出,用于奇偶校验(p)。
-===3.3 oc8051_b_register===+==2.2.3 oc8051_b_register==
 B寄存器是简单的位寻址寄存器没有特殊功能 B寄存器是简单的位寻址寄存器没有特殊功能
-===3.4 oc8051_psw===+==2.2.4 oc8051_psw==
 这个模块包含程序状态字。除了标准输入外,它还有 这个模块包含程序状态字。除了标准输入外,它还有
 来自ACC的信号p(奇偶);\\ 来自ACC的信号p(奇偶);\\
行 160: 行 161:
 置位要写入寄存器的对应信号\\ 置位要写入寄存器的对应信号\\
 {{::​oc8051-psw.png|}}\\ {{::​oc8051-psw.png|}}\\
-===3.5 oc8051_dptr===+==2.2.5 oc8051_dptr==
 该模块包含16位宽数据指针。它有以下内容:\\ 该模块包含16位宽数据指针。它有以下内容:\\
   * 两个8位输出(data_hi和data_lo)   * 两个8位输出(data_hi和data_lo)
行 166: 行 167:
   * 2位宽的信号,当指令需要使用DPTR作为十六位宽寄存器时,该信号被激活   * 2位宽的信号,当指令需要使用DPTR作为十六位宽寄存器时,该信号被激活
 该寄存器不可位寻址。 该寄存器不可位寻址。
-===3.6 oc8051_sp===+==2.2.6 oc8051_sp==
 该模块表示堆栈指针。 除了标准输入外,它还有两个连接到oc8051_decoder的输入信号。 这两个输入信号定义了读或者写的地址。 该模块表示堆栈指针。 除了标准输入外,它还有两个连接到oc8051_decoder的输入信号。 这两个输入信号定义了读或者写的地址。
-===3.7 oc8051_ports===+==2.2.7 oc8051_ports==
 该模块负责输入输出端口。 \\ 该模块负责输入输出端口。 \\
 它有四个8位输入总线和四个8位输出总线。 该信号用于与外界通信。 模块输入也是8位当前地址。 该模块还具有rmw信号,该信号指示该指令是否是所谓的读 - 修改 - 写指令。 根据这些指令,我们不读取模块的输入引脚,而是读取输出端口的寄存器。\\ 它有四个8位输入总线和四个8位输出总线。 该信号用于与外界通信。 模块输入也是8位当前地址。 该模块还具有rmw信号,该信号指示该指令是否是所谓的读 - 修改 - 写指令。 根据这些指令,我们不读取模块的输入引脚,而是读取输出端口的寄存器。\\
行 183: 行 184:
 - CLR PX.Y \\ - CLR PX.Y \\
 - SETB PX.Y \\ - SETB PX.Y \\
-===3.8 oc8051_tc===+==2.2.8 oc8051_tc==
 该模块描述oc8051定时器。有两个定时器:定时器/​计数器0(T0/​C0)和定时器/​计数器1(T1/​C1)。两个定时器都是16位字长,每个定时器由两个8位寄存器表示(T/​C 0为TL0和TH0,T/​C1为TL1和TH1)。该模块还包含SFR TMOD,它定义了定时器模式。\\ 该模块描述oc8051定时器。有两个定时器:定时器/​计数器0(T0/​C0)和定时器/​计数器1(T1/​C1)。两个定时器都是16位字长,每个定时器由两个8位寄存器表示(T/​C 0为TL0和TH0,T/​C1为TL1和TH1)。该模块还包含SFR TMOD,它定义了定时器模式。\\
 {{::​oc8051-tmod.png|}}\\ {{::​oc8051-tmod.png|}}\\
行 192: 行 193:
   * 模式2:THx表示8位计数器,溢出时填充TLx内容   * 模式2:THx表示8位计数器,溢出时填充TLx内容
   * 模式3:在这种模式下,t / c1只保持恒定值。 而t / c0用作两个独立的8位计数器。 TH0使用来自timer0的控制信号(TF0中的TR0),而TL0使用来自timer1的控制信号(TF1中的TR1)。   * 模式3:在这种模式下,t / c1只保持恒定值。 而t / c0用作两个独立的8位计数器。 TH0使用来自timer0的控制信号(TF0中的TR0),而TL0使用来自timer1的控制信号(TF1中的TR1)。
-===3.9 oc8051_int===+==2.2.9 oc8051_int==
 中断模块。该模块接收中断请求,然后根据已定义的状态,调度请求到处理器中。这里定义了五种不同中断源,每一种的中断函数都有自己的独一的地址。\\ 中断模块。该模块接收中断请求,然后根据已定义的状态,调度请求到处理器中。这里定义了五种不同中断源,每一种的中断函数都有自己的独一的地址。\\
 These addresses are: These addresses are:
行 208: 行 209:
 {{::​oc8051-ip.png|}}\\ {{::​oc8051-ip.png|}}\\
 模块有五个中断输入,每个对应一个中断源。 还有两个输入信号,reti和ack。中断结束时reti置位,当处理器打断向量中断任务时,信号ack置位。 模块还具有8位总线,用于读取中断向量地址。\\ 模块有五个中断输入,每个对应一个中断源。 还有两个输入信号,reti和ack。中断结束时reti置位,当处理器打断向量中断任务时,信号ack置位。 模块还具有8位总线,用于读取中断向量地址。\\
-===3.10 oc8051_uart===+==2.2.10 oc8051_uart==
 该模块包含oc8051串行接口(uart)。 除标准输入外,它还具有接收输入信号(rxd)和发送输入信号(txd)。 这两个信号也是处理器的输出。 还有一个timer1溢出输入和一个中断输出。模块包含三个SFR:串行控制(scon),串行数据缓冲器(sbuf)和功率控制(pcon)。 该模块包含oc8051串行接口(uart)。 除标准输入外,它还具有接收输入信号(rxd)和发送输入信号(txd)。 这两个信号也是处理器的输出。 还有一个timer1溢出输入和一个中断输出。模块包含三个SFR:串行控制(scon),串行数据缓冲器(sbuf)和功率控制(pcon)。
 串口控制寄存器 (SCON)\\ 串口控制寄存器 (SCON)\\
行 218: 行 219:
   * 模式3:传输11位:起始位,8个数据位,可编程的第9位和停止位。 波特率是可变的。   * 模式3:传输11位:起始位,8个数据位,可编程的第9位和停止位。 波特率是可变的。
 当处于模式1或3时,需要timer1来计算波特率(波特率=(2 ^ smod / 64)*(定时器1溢出率))。 当处于模式1或3时,需要timer1来计算波特率(波特率=(2 ^ smod / 64)*(定时器1溢出率))。
-===3.11 oc8051_indi_addr===+==2.2.11 oc8051_indi_addr==
 该模块不包含任何SFR,但它仍包含数据存储器的一部分。 来自所有寄存器组R0和R1的数据。 该寄存器用于间接寻址。输入在特定的寄存器缓冲区占据两位bit,操作码的最后一部分用来选择寄存器R0或R1。因此在直接寻址中,在第一时钟阶段,操作数已经就位,没有必要停止流水线。 该模块不包含任何SFR,但它仍包含数据存储器的一部分。 来自所有寄存器组R0和R1的数据。 该寄存器用于间接寻址。输入在特定的寄存器缓冲区占据两位bit,操作码的最后一部分用来选择寄存器R0或R1。因此在直接寻址中,在第一时钟阶段,操作数已经就位,没有必要停止流水线。
-===3.12 oc8051_ram_sel===+==2.2.12 oc8051_ram_sel==
 该模块代表多路复用器,基于该复用器,读入的指针能够将正确的数据传给数据总线。这样就可以选择存储器中的数据或者特殊寄存器中的数据。 该模块代表多路复用器,基于该复用器,读入的指针能够将正确的数据传给数据总线。这样就可以选择存储器中的数据或者特殊寄存器中的数据。
-====4 多路复用器====+===2.3 多路复用器===
 总线管理是基于多路复用器的,他们的主要特点是选择输入信号并转换成相应的输出信号。输入信号来自oc8051_decoder (译码)模块的八位宽的信号。 总线管理是基于多路复用器的,他们的主要特点是选择输入信号并转换成相应的输出信号。输入信号来自oc8051_decoder (译码)模块的八位宽的信号。
-===4.1 oc8051_alu_src1_sel===+==2.3.1 oc8051_alu_src1_sel==
 这个模块用来选择第一个ALU操作数。他们来自立即操作数,ACC,有效的内部空间数据或外部空间数据。 这个模块用来选择第一个ALU操作数。他们来自立即操作数,ACC,有效的内部空间数据或外部空间数据。
-===4.2 oc8051_alu_src2_sel===+==2.3.2 oc8051_alu_src2_sel==
 这个模块用来选择第二个ALU操作数。他们来自立即操作数,ACC,有效的内部空间数据或外部空间数据或者零。 这个模块用来选择第二个ALU操作数。他们来自立即操作数,ACC,有效的内部空间数据或外部空间数据或者零。
-===4.3 oc8051_alu_src3_sel===+==2.3.3 oc8051_alu_src3_sel==
 这个模块用来选择第三个ALU操作数。他们来自程序计数器或者DPTR。 这个模块用来选择第三个ALU操作数。他们来自程序计数器或者DPTR。
-===4.4 oc8051_cy_select===+==2.3.4 oc8051_cy_select==
 选择把以下哪里的进位送给ALU,\\ 选择把以下哪里的进位送给ALU,\\
 (1)来自PSW \\ (1)来自PSW \\
行 236: 行 237:
 (3)0 \\ (3)0 \\
 (4)1 \\ (4)1 \\
-===4.5 oc8051_ext_addr_sel===+==2.3.5 oc8051_ext_addr_sel==
 选择外部空间地址:R0或R1 (等同于间接寻址) 或者 DPTR。 选择外部空间地址:R0或R1 (等同于间接寻址) 或者 DPTR。
-===4.6 oc8051_immediate_sel===+==2.3.6 oc8051_immediate_sel==
 选择立即操作数。有两个输出,一个用作第一个ALU操作数,另一个用作第二个ALU操作数。可以在PC (程序计数器),第二个或第三个指令字节之中选择。 选择立即操作数。有两个输出,一个用作第一个ALU操作数,另一个用作第二个ALU操作数。可以在PC (程序计数器),第二个或第三个指令字节之中选择。
-===4.7 oc8051_ram_rd_sel===+==2.3.7 oc8051_ram_rd_sel==
 选择读地址: 选择读地址:
 (1)寄存器(R0-R7);\\ (1)寄存器(R0-R7);\\
行 247: 行 248:
 (4)直接地址。\\ (4)直接地址。\\
 当选择地址寄存器时,只有五个位的数值被使用(前三个位的数值总是零)。 当选择地址寄存器时,只有五个位的数值被使用(前三个位的数值总是零)。
-===4.8 oc8051_ram_wr_sel===+==2.3.8 oc8051_ram_wr_sel==
 选择写地址: 选择写地址:
 (1)寄存器(R0-R7); (1)寄存器(R0-R7);
行 255: 行 256:
 (5)DPTR; (5)DPTR;
 (6)B寄存器。 (6)B寄存器。
-===4.9 oc8051_rom_addr_sel===+==2.3.9 oc8051_rom_addr_sel==
 选择程序空间地址: 选择程序空间地址:
 (1)PC; (1)PC;
 (2)DPRT (只在MOVC指令下有效)。 (2)DPRT (只在MOVC指令下有效)。
- +====3 指令执行==== 
-\\ +要获得完整的概述,我们需要查看三个时钟周期。\\ 
-===参考来源===: \\ +第一个时钟周期:尚未获取指令。基于PC先前值和操作码,计算出新的PC值。作为下一条指令的地址。在下一步中,从程序存储器中获取新的操作码和操作数。\\ 
-opencores的设计文档 ​oc8051_design ​>  ​\\ +第二个时钟周期:同时是第一个执行周期。在此期间,操作代码被发送到oc8051_pc模块,其中计算新PC,并且发送到oc8051_decoder模块,其中置位所有控制信号。除内部数据存储器读地址信号外的所有信号都会延迟一个时钟周期(使用oc8051_regX模块)。通过这种延迟,当下一个操作数从内部数据存储器被读取后,控制信号和其他可能的立即操作数被保存到寄存器中。\\ 
-李全利老师主编的《单片机原理及接口技术》 \\  +第三个时钟周期:同时是第二个执行周期。在这一周期信号到达目的地。使用oc8051_alu_src1和oc8051_alu_src2,选择ALU操作数。执行ALU中的操作,并将结果写入存储器中的选定地址。\\ 
-网友oldbeginner的开源软核学习笔记:http://​xilinx.eetop.cn/​space.php?​uid=1214938&​op=bbs \\ +{{::​oc8051-指令执行.gif|}} \\ 
-网友leishangwen的《DE2上使用OC8051运行点灯程序》:  \\ +大多数指令的执行过程如上所述。 程序跳转指令和程序存储器读取指令(MOVC)例外。在接下来的章节中,我们将介绍指令组及其特定功能。 
-https://​download.csdn.net/​download/​leishangwen/​5173363 \\ +===3.1 算术和逻辑指令=== 
-由于水平所限,难免有不对之处,欢迎指正。 \\+这些指令的主要特征是我们必须定义ALU操作数和ALE运算。 除了两个例外:MUL(乘法)指令Div(除)指令。 这两个指令的不同之处在于结果。 当执行MUL或DIV时,我们得到16位结果,其中一半保存到B寄存器(result1),后半部分(result2)保存到ACC。 如果结果通常写入B寄存器,则设置wad2信号,并将第二个结果写入ACC,即可实现此目的。\\ 
 +另一个例外是INC DPTR指令,它对16位DPTR寄存器进行寻址。 前8位宽的值被发送给ALE source3,0被转发到source2,输入进位被设置为1,然后运算执行。\\ 
 +可以执行的指令\\ 
 +-       ​ADD ​      ​add\\ 
 +-       ​ADDC ​   add with carry\\ 
 +-       ​SUBB ​    ​subtract with carry\\ 
 +-       ​INC ​       increase by 1\\ 
 +-       ​DEC ​      ​decrease by 1\\ 
 +-       ​MUL ​     multiply\\ 
 +-       ​DIV ​       divide\\ 
 +-       ​DA ​        ​decimal adjust\\ 
 +-       ​ANL ​      ​logical and\\ 
 +-       ​ORL ​      ​logical or\\ 
 +-       ​XRL ​      ​logical xor\\ 
 +-       ​CLR ​      ​clear\\ 
 +-       ​RL ​         rotation left\\ 
 +-       ​RLC ​      ​rotation left with carry\\ 
 +-       ​RR ​         rotation right\\ 
 +-       ​RRC ​      ​rotation right with carry\\ 
 +-       ​SWAP ​   swap bits\\ 
 +===3.2 ​ 数据传输指令=== 
 +该组包含不更改数据值的指令,它们只是将数据传输到另一个内存位置。 ALU操作固定为oc8051_alu_nop,它仅将数据从输入传输到输出,从而将数据写入所需位置。 例外是使用ALE操作oc8051_alu_xch的switdh指令(XCH和XCHD)。\\ 
 +该指令组还包含外部存储器处理的指令。 下图显示了管理外部数据存储器的内核细节。 读取地址选择oc8051_ext_addr_sel multiplekser,输入数据在下一个时钟周期可用。 数据像multikser上的选项一样可用,我们选择ALE1.通过正常程序,数据被写入内部存储器。 写入时我们只需要地址和write_x信号,输出引脚上应该有来自ACC的信号。\\ 
 +{{::​oc8051-数据传输指令.gif|}}\\ 
 +特殊指令也用来从程序存储器传送数据。这次使用另一个选择器(oc8051_rom_addr_sel)来选择地址,该选择器不会发送PC 的值,而是发送ALU 运算结果给输出。下一时钟周期收到的数据作为立即操作数。这个指令花费两个时钟周期。\\ 
 +- MOV\\ 
 +- PUSH\\ 
 +- POP\\ 
 +- XCH\\ 
 +- XCHD\\ 
 +===3.3 位操作指令=== 
 +位操作指令和逻辑运算指令类似,区别在于他们用位输入和ALU进位代替了ALU 输入,结果可以通过ALU 输出。\\ 
 +使用位指令时,需要特别留意选择ALU运算。利用oc8051_cy_select选择ALU的进位输入,我们有四个选项PSW (PSW.7),空间的位输出,逻辑1或逻辑0。\\ 
 +前两个选项用在运算中,后两个用来给特定位的置位(或复位)\\ 
 +{{::​oc8051-位操作指令.gif|}}\\ 
 +该组还包含跳转指令(JC,JNC,JB,JNB和JBC),下一节将对此进行更详细的描述。\\ 
 +Other instructions in this group are:\\ 
 +-       ​ANL\\ 
 +-       ​ORL\\ 
 +-       ​MOV\\ 
 +-       ​CLR\\ 
 +-       ​SETB\\ 
 +-       ​CPL\\ 
 +===3.4 程序跳转=== 
 +转移指令和其它指令不太类似。这些指令改变PC 值,以致不得不停止流水线,等待从新地址取得第一条指令。利用花费时间的不同,将这类指令分成三组:\\ 
 +第一组指令需要两个时钟周期。这组指令让新的PC 值作为立即操作数。利用这组指令,新的数值被写入 PC,然后等待新的指令。\\ 
 +第二组指令需要三个时钟周期。该组指令是变址寻址(间接)转移指令,它是将累加器A中的8位数和数据指针DPTR中的16位数相加,形成16位的转移目标地址送给PC,而不改变A和DPTR的内容,不影响标志位。\\ 
 +Instructions in this group are:\\ 
 +-       ​JC\\ 
 +-       ​JNC\\ 
 +-       ​JB\\ 
 +-       ​JNB\\ 
 +-       ​JBC\\ 
 +-       ​SJMP\\ 
 +-       ​JMP\\ 
 +-       ​JZ\\ 
 +-       ​JNZ\\ 
 +最后一组指令需要四个时钟周期。\\ 
 +These instructions are:\\ 
 +-       CJNE, 类似于前一组的指令,但需要另一个时钟周期来设置进位标志\\ 
 +-       ​RET\\ 
 +-       ​RETI\\ 
 +===3.5 寻址模式=== 
 +控制寻址模式的有两个模块:oc8051_ram_rd_sel 和 oc8051_ram_wr_sel。\\ 
 +利用这两个模块,我们可以选择要读取的地址或要写入的地址。操作数利用oc8051_immediate_sel 选择。\\ 
 +利用 oc8051_alu_src1_sel 和 oc8051_alu_src2_sel ,可以选择是从数据存储器或是ACC或是理解操作数中,读取数据\\ 
 +不同的寻址模式:\\ 
 +- 直接寻址:我们选择具有多路复用器的直接地址(读取OC8051_RRS_D - 操作数2,写入OC8051_RWS_D操作数2和OC8051_RWS_D3操作数3),并将来自程序存储器的数据发送到总线。\\ 
 +- 间接寻址:对于间接寻址,使用来自所选寄存器组的寄存器R0和R1,模块oc8051_indi_addr用于此,模块保存可能有用的寄存器,然后考虑选择哪个寄存器组,操作码的最后一位选择寄存器我们可能需要。用于地址选择的多用户(oc8051_RRS_I和oc8051_RWS_I)必须设置为间接寻址。堆栈管理也属于这组指令。使用模块oc8051_RRS_SP和oc8051_RWS_SP,我们在寻址总线上获得堆栈指针值,模块oc8051_sp用于增加或减少指针值。\\ 
 +- 寄存器寻址:当我们使用寄存器寻址时,必须使用OC8051_RRS_RN和OC8051_RWS_RN多路复用器选择地址。最后的物理地址从操作码的最后三位和两位用于选择寄存器组。高三位始终为零。\\ 
 +- 特殊寄存器寻址:这些指令主要针对累加器。选择ACC读取ALU源选择复用器。使用oc8051_ram_wr_sel 复用器选择写入ACC,这提供ACC写入作为选项之一(OC8051_RWS_ACC)。还有一些特定于B寄存器或DPTR的指令。该指令在oc8051_op_select模块中被截获,所需地址被放入第二结果总线并被视为直接寻址。\\ 
 +- 立即数寻址:在此寻址模式下,常量的值跟在操作码之后。由于限制,总是从内存中传递三个字节,因此它们也是立即可用的。我们选择与oc8051_immediate_sel 复用器一起使用哪一个,然后选择ALU源的立即操作数。该组还包括程序计数器,因此它也可用于调用子程序和相对寻址。\\ 
 +- 索引寻址:该寻址模式仅在寻址程序存储器时使用。在此模式下,使用oc8051_rom_addr_sel 复用器。在计算下一个地址时,将发送ALE结果而不是PC。数据在下一个时钟周期中作为立即操作数被接收。\\ 
 +{{::​oc8051-寻址模式.gif|}}\\ 
 +====4 中断==== 
 +由模块oc8051_int管理中断处理。 该模块截取中断,定义中断程序的地址并向下一个模块发送中断请求。 如果中断被启用且没有更高(或相同)优先级的任何一个已经处理,则模块设置int信号并将中断程序地址写入int_v总线。 该中断请求被发送到oc8051_op_select模块,该模块停止当前程序的执行并开始执行LCALL指令。 当中断程序结束时(使用RETI指令),oc8051_decoder设置reti信号并与oc8051_int模块通信中断处理完成,因此程序可以在此优先级上中断\\ 
 +{{::​oc8051-中断.gif|}} 
 +====仿真和移植==== 
 +{{::​使用quartus和modelsim仿真oc8051.pdf|}} 
 +====参考来源==== 
 +  * opencores的设计文档{{::oc8051_design.doc|}} ​\\ 
 +  ​* ​李全利老师主编的《单片机原理及接口技术》 \\  
 +  ​* ​网友oldbeginner的开源软核学习笔记:http://​xilinx.eetop.cn/​space.php?​uid=1214938&​op=bbs \\ 
 +  ​* ​网友leishangwen的《DE2上使用OC8051运行点灯程序》:https://​download.csdn.net/​download/​leishangwen/​5173363 \\ 
 +  ​* ​由于水平所限,难免有不对之处,欢迎指正。 \\