基于vhdl语言的risc-cpu系统设计内容摘要:

elsif ena=39。 139。 then accum=d。 end if。 end if。 end process。 end art。 图 34 为累加器各信号仿真波形图。 如图所示, 当复位信号 reset=‘ 0’ 、使能信号 ena=‘ 1’ 时,在每个 clk 上升沿到来后, ACC 接收来自于数据总线 d[7..0]的数据 (00、 0 0 0 04);当 ena=‘ 0’ , ACC 保持 04 不变;当 ena 又变为有效信号后, ACC 继续接受来自数据总线的数据;当 reset=‘ 1’ , ACC 复位,输出 accum清零。 算术逻辑运算单元 (ALU) ALU 的功能十分强大,它不仅可以进行逻辑“与”“或”“异或”等逻辑运算,还可以进行加、减算术运算。 除此之外还可以进行停 机、跳转等操作。 逻辑运算单元模块引脚图如 35 所示。 34 累加器各信号波形 图 35 算术逻辑运算单元 第三 章 八位 RISCCPU各摸块设计及仿真 13 图 35 中 clk 为 ALU 的时钟信号,由时钟电路生成的 alu_clk 信号提供; opcode 为操作码输入端,取自指令寄存器的高 3 位, ALU 根据输入的不同操作码进行不同的操作; data 输入来自数据总线上的数据; accum端输入来自累加器的一个操作数; alu_out 端用来保存或输出操作后的结果; zero 用于标志累加器的结果 accum 是否为 0,如果为 0,则 zero 为 1,否则 zero 为 0。 在程序设计时,首先定义指令的编码,然后规定各个指令所对应的操作,编写 程序时采用 CASE 语句实现。 CASE 语句用来描述总线或编码、译码的行为,从许多不同语句的序列中选择其中之一执行,属于数据流描述法,是结构体描述方法的一种。 当然此处也可以采用 IF 语句实现。 没有采用 IF 语句的原因有以下几个:首先 CASE 语句的可读性比 IF 语句要强的多,程序的阅读者很容易找出条件式和动作的对应关系。 其次在 CASE语句中, WHEN 语句可以颠倒次序而不至于发生错误 : 而在 IF 语句中,颠倒条件判别的次序往往会使综合的逻辑功能发生变化。 另外,在 IF 语句中,先处理最起始的条件,如果不满足,再处理下一个条件:而 在 CASE语句中,没有值的顺序号,所有值是并行处理的,这样就缩短了程序的执行时间。 算术逻辑运算单元程序及仿真波形如下, library ieee。 use。 use。 entity alu is port(clk: in std_logic。 opcode: in std_logic_vector(2 downto 0)。 data,accum: in std_logic_vector(7 downto 0)。 zero: out std_logic。 第三 章 八位 RISCCPU各摸块设计及仿真 14 alu_out: out std_logic_vector(7 downto 0))。 end alu。 architecture behave of alu is signal alu_out_latch: std_logic_vector(7 downto 0)。 constant NOP: std_logic_vector(2 downto 0):=000。 constant JZ: std_logic_vector(2 downto 0):=001。 constant ADD: std_logic_vector(2 downto 0):=010。 constant ANL: std_logic_vector(2 downto 0):=011。 constant XRL: std_logic_vector(2 downto 0):=100。 constant MOV: std_logic_vector(2 downto 0):=101。 constant MEM: std_logic_vector(2 downto 0):=110。 constant AJMP: std_logic_vector(2 downto 0):=111。 begin zero=39。 139。 when accum=00000000 else 39。 039。 process(clk) variable temp:std_logic_vector(2 downto 0)。 begin temp:=opcode。 if clk39。 event and clk=39。 139。 then case temp is when NOP=alu_out_latch=accum。 when JZ=alu_out_latch=accum。 when ADD=alu_out_latch=data+accum。 第三 章 八位 RISCCPU各摸块设计及仿真 15 when ANL=alu_out_latch=data and accum。 when XRL=alu_out_latch=data xor accum。 when MOV=alu_out_latch=data。 when MEM=alu_out_latch=accum。 when AJMP=alu_out_latch=accum。 when others=alu_out_latch=XXXXXXXX。 end case。 end if。 end process。 alu_out=alu_out_latch。 end behave。 仿真波 形如 图 36 所示 : 在此仿真波形图中 , clk 为时钟信号输入端口, zero 为判 accum 是否为零的输出端口。 opcode 为操作码输入端, data 为数据输入端 , accum 为另一输入端口,它接累加器的输出端。 opcode 不同的值代表不同的操作,在此图中,假设 data 为“ 1”(十进制), accum 为“ 2”,两者相与为“ 0”,相加为“ 3”,跳转时则输出 accum 的值“ 2”,数据传输时输出 data 的值“ 1”。 图 36 算术逻辑运算单元仿真波形 第三 章 八位 RISCCPU各摸块设计及仿真 16 指令寄存器 指令寄存器用来寄存指令,其引脚图如图 37 所示。 指令寄存器的触发时钟是 clk1。 clk1 的上升沿触发,寄存器开始工作。 每条指令为两个字节,即 16 位。 高 3 位是操作码,低 13 位是地址。 本设计的数据总线为 8位,所以每条指令需要取两次,先 取高 8 位,后取低 8 位。 由状态变量 state来标志从数据总线上取来的数据是高 8 位还是低 8 位。 如果 state 为 0 表示取得的是高 8 位,存入高 8 位寄存器,同时将变量 state 置为 1。 下次再寄存时,由于 state 为 1,可知取得的是低 8 位,存入低 8 位寄存器中,同时将 state 置为 0。 由于数据总线既可以传输指令也可以传输数据,而且只有指令需要寄存到指令寄存器中,因此需要一个信号指示是否进行寄存。 图中 ena 引脚用来控制是否寄存。 当数据总线传输的是指令时, ena 端由控制电路置为1,指令寄存;如果数据总线传输的是数 据,则 ena 为 0, 指令寄存器停止工作。 指令寄存时,分为高 3 位和低 13 位分别寄存到操作码寄存器 opcode和地址寄存器 instr_addr。 指令寄存器源程序如下: library ieee。 use。 entity reg is port(clk, reset, ena: in std_logic。 data: in std_logic_vector(7 downto 0)。 opcode: out std_logic_vector(2 downto 0)。 图 37 指令寄存器 第三 章 八位 RISCCPU各摸块设计及仿真 17 instr_addr: out std_logic_vector(12 downto 0))。 end reg。 architecture behave of reg is signal opc_iraddrs: std_logic_vector(15 downto 0)。 begin process(clk) variable state: std_logic:=39。 039。 begin if(clk39。 event and clk=39。 139。 )then if reset=39。 139。 then opc_iraddrs=(others=39。 039。 )。 elsif ena=39。 139。 then case state is when 39。 039。 =opc_iraddrs(15 downto 8)=data。 state:=39。 139。 when 39。 139。 =opc_iraddrs(7 downto 0)=data。 state:=39。 039。 when others=null。 end case。 else state:=39。 039。 end if。 end if。 第三 章 八位 RISCCPU各摸块设计及仿真 18 end process。 opcode=opc_iraddrs(15 downto 13)。 instr_addr=opc_iraddrs(12 downto 0)。 end behave。 仿真波形如图 38 如下: 在此仿真波形图中, clk 为时钟输入信号, ena 为使能输入端口, reset 为复位 端口,这里假设 data 传输的一直是“ 21”(十六进制),则当 state 为 0 时 ,传输高八位,当 state 为 1 时,传输低八位。 其中 13 至 15 位存入 opcode 中, 0至 12 位存入 str_addr 中。 所以这里的 opcode 为“ 1”, str_addr 为“ 0121”。 状态控制电路 状态控制电路是 CPU 的控制核心。 用于产生一系列的控制信号,来控制 各部件的启动或者停止。 clk clk8 由时钟产生电路产生; reset 为高电平时,复位状态控制电路所有输出信号; opcode 为操作码输入端,取自指令寄存器的高三位; pc_clk 作为程序计数器的时钟信号; acc_ena 输出到累加器的使能端; pc_ena 为指令寄存器的使能信号,控制指令寄存器的启、停; datactrl_ena 作为数据控制电路的使能信号; idle 为停机信号,输出到片外。 图 38 指令寄存器仿真波形 第三 章 八位 RISCCPU各摸块设计及仿真 19 如果将状态控制电路作为一个整体进行程序编写,有许多语句需要反复描述。 这样降低了程序的可读性,而且在硬件实现时也会增加不必要的重复的逻辑电路。 因此将状态控制电路又分为状态机和状态控制器两部分。 状态控制器产生使能信号 ena 控制状态机的启、停。 当复位信号 reset有效时,状态控制器将 ena 置 零,从而使状态机停止工作,各输出信号复位。 状态控制器中当复位脉冲过后, clk8 上升沿到来, ena 输出为 1,否则为 0。 下面重点说明状态机的设计。 此设计中,指令周期由 8 个时钟周期组成,每个时钟周期完成固定的工作。 因此状态控制器有 8 个状态,当前状态由某一变量记录,此变量的值就是当前这个指令周期中经过的时钟数(从零开始记录)。 各时钟周期,CPU 进行的操作如下: 第 0 个时钟,从 ROM 读取指令。 由于指令长度为 16 位,数据总线为8 位,所以读取一条指令需要两个时钟周期。 第 0 个时钟读取指令的高 8图 39 状态控制电路 图 310 状态控制器 图 311 状态机 第三 章 八位 RISCCPU各摸块设计及仿真 20 位代码 ,并存入指令寄存器。 此时状态机使读信号 rd 和 reg_ena 输出 1(表示高电平 ),其余全部为 0(表示低电平 )。 第 1 个时钟,从 ROM 读取指令的低 8 位代码并 存入指令寄存器。 此时钟结束后一条指令读完,程序指针将指向下一个存储单元。 因此与上一时钟相比 pc_clk 也从 0 变为 1,使程序计数器 (PC)增 1。 第 2 个时钟,空操作。 所有的输出信号均为 0。 第 3 个时钟,开始分析前两个时钟读取的指令。 如果操作符为 NOP ,则输出信号 idle 为高;如果操作符不为 NOP,则 PC 增 1,指向下一条指令,其他各控制线输出为零。 第 4 个时钟 ,若取得的操作符为 ANL, ADD, XRL 或 MOV,则 rd输出 1,读取相应地址的数据,地址由所读取的指令的低 13 位给出;若为AJMP,则 pc_en。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。