前人种树9-华电计算机组成原理实验

前言

        之所以开设“前人种树”专栏,是因为笔者十分推崇某位牛马前辈,当初刚入学对实验一筹莫展时偶然接触到这位前辈分享的材料,且不说对我有没有帮助,反正从那以后我经常看他分享的实验材料。慢慢地看多了之后才发现,原来这位前辈发材料的初衷可能没有我想的那么高尚,不是为了作为前人种树让后来人乘凉的,纯纯为了炫耀。为什么这么说呢?因为基本上他所有的公开分享的材料,都是要么缺斤少两,要么就在某个细节上把原来正确的改成错的。而他收费恰米的材料,都是完全正确可以直接拿来用的。

        所以我呢,就把自己的实验材料也做个分享,不缺斤少两,更不故意把对的改成错的让后面的学弟们找半天,故意捉弄人嘛这不是?【楽】希望我这个种树的前人能对后人们有些许帮助,也希望各位是在弄懂我的东西后才去套用甚至自创。

        扯远了,计组实验是小组实验,一般三到四个人一组,得上硬件实验机房去烧板子,所谓烧板子就是用一堆线按规定连接电脑和电路板,在电脑的相应软件上编程后烧录进板子。有四个实验,难度依次递增,前两个必做,能拿到及格,后两个选做一个,做第三个能拿良,做第四个能冲优。笔者带了两个组员,做的是前三个,拿了良。

        实验报告放下文,至于具体细节和知识,笔者敢打包票,全忘了,没错,全忘光了。。。因为笔者是走纯软件路线的,这些个硬件相关的知识老师不教,做实验纯靠自学,本来就是似懂非懂半桶水功夫,实验做完之后也根本用不到,且笔者如今回首整理资料,时间间隔久远,就忘了。所以各位看官有不懂的地方问笔者大概率是不会的,但可以私信笔者要代码,笔者会尽可能多地把当年的所有资料发你,不过里面的内容良莠不齐,有用的代码烦请各位自己找找吧,肯定是包含在里面的。

ac64605556282d9d31219c1b2fea7869.jpeg

实验一 运算器设计实验

  •  目的与要求
  1. 目的
    1. 熟悉VHDL硬件描述语言及开发环境,了解硬件系统开发的基本过程。
    2. 掌握ALU基本设计方法和运算器的数据传送通路。
    3. 掌握内存(RAM)的访问时序和方法。
    4. 理解总线数据传输的基本原理。
    5. 理解控制器的功能,加深对多周期CPU的控制器与指令周期的理解。
  2. 要求

2.1运用所学的知识和方法采用最佳方案完成实验设计。

    1. 编写简洁代码完成实验要求内容。
    2. 认真书写实验报告,包括实验目的、实验内容、实验设计方案、实验仿真结果等。

二、实验正文

实验内容

    1. 编程实现16位ALU的定点算术运算、逻辑运算等基本功能,ALU的数据输入A、B的长度也为16位,操作码OP位4位,实验班上输入的码是右边到左边顺序为15~0。
    2. 最终结果能实现一个状态机,根据状态机的状态变化来输入操作码和操作数,并最终实现不同的运算,将结果和标志位在实验板上对应物理位置的灯呈现出来。

实验步骤

    1. 创建空白工程
    2. 添加源文件及引脚约束文件等
    3. 编辑源代码
    4. 在实验板子上有红色大字(七段数码管)“0,1,2,3,4”表示输入的步骤,然后输入操作码后决定运算功能,再输入数据进行演示,最后在红色大字旁边的16个LED灯上有对应的亮或者灭,分别是结果和标志位对应的结果。

部分代码

begin              

                rst<='0';

      wait for clk_period*10;

                rst<='1';

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                INPUT<="0000000000000001";

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                INPUT<="0000000000000001";

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                INPUT<="0000000000000001";

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                INPUT<="0000000000000000";

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                wait for clk_period*10;

               

                clk<='0';

                wait for clk_period*10;

                clk<='1';

                wait for clk_period*10;

      wait;

   end process;

实验结果

输入数据

实际输出

与预期一致性

操作码

操作数A

操作数B

运算结果

标志位

0110XOR

1001010010110100

0101001000110101

1100011010000001

0010

一致

0111NOT

1101011010110100

0000000000000000

0010100101001011

0001

一致

1001SLL

1001010010110100

0000000000000101

1001011010000000

0010

一致

思考题

    1. ALU进行算术逻辑运算所使用的电路是组合逻辑电路还是时序逻辑电路?

答:组合逻辑电路。

    1. 如果给定了A和B的初值,且每次运算完后结果都写入到B中,再进行下次运算。这样一个带暂存功能的ALU要增加一些什么电路来实现?

答:增加tmp暂存器和AC累加器。

三、综合实验总结

  1. 实验难点
      1. 在输出标志位时,如何通过操作数和操作结果判断标志位;
      2. 在判断标志位cFlags时,需要仔细考虑指令对标志位的影响及其背后原因,尤其是ADC指令和SBB指令,需要记录每一位的进位并利用循环结构得到最终结果和进位标志位(类似全加器原理)。
      3. 在判断溢出标志位oFlags时,要灵活掌握操作数和运算结果之间符号位的变化和OF标志位的关系,以便正确设置标志位。
      4. 在进行移位运算时,要将需要被移位的操作数A的数据类型转换为位矢量类型方可移位,将移位操作数转换成整数。
  2. 心得体会

指令种类不少,需要用心学习每一条指令背后的原理才能更好地设计出ALU的逻辑。

  1. 个人分工

本人在此实验中负责所有工作,代码编写、硬件操作验证等均由本人完成,并且教会其他两位组员实验板的操作及代码原理。

实验二 存储器实验

一、目的与要求

使用教学计算机上的FPGA芯片,设计一个状态机和内存读写逻辑,完成对存储器RAM的访问。

  1. 写RAM1。将手拨开关上的数据,写入到RAM1的相应存储单元中,在LED灯上分别显示地址和数据。
  2. 读RAM1。按CLK键,逐个将刚写入的数据从存储单元中读出,送到LED上显示。

二、实验正文

实验内容

使用教学机上的FPGA芯片,设计一个状态机和内存读写逻辑,完成对存储器RAM的访问。

实验步骤

  • 输入信号
  1. 拨码开关决定读写地址或数据;
  2. RAM的数据线、地址线;
  3. LED灯,用来显示从内存中读出的数据。
  • 状态机
  1. 读写状态控制的状态机:控制当前控制器是否处于读或写状态;
  2. 内存读、写周期的状态机:根据时钟进行跳转,控制读写的过程;
  3. 在实验过程中可以使用七段数码管检测状态及当前的状态,发光二极管只有16个,可以只显示地址的低8位和数据的低8位。
  • 验证过程
  1. 将编译好的内存控制器对应实验板烧入;
  2. 用手拨动拨码开关,预设一个值,每个写周期,作为写入内存的数据;每个读周期,该值作为内存地址,从该内存位置处读出数据。该预设值在同一个读/写周期内不变;
  3. 写周期,LED灯显示当前写入的地址,读周期,LED灯显示从内存中读出的数据;
  4. 注意观察LED灯上地址和数据的变化,是否符合实验的设计要求;
  5. 记录实验结果;

部分代码

process(rst,clk)

begin

    if rst='0' then --复位信号,全部清零

       state<="000";

       output<="0000000000000000";

       add<="000000000000000000";

       data<="0000000000000000";

       en<='0';

       oe<='0';

       rw<='0';

    else

       if clk'event and clk='1' then--时钟进入上升沿

            if state="000" then--选择读或者写

                         output<=input;

                  case input(2 downto 0) is

                      when "001" =>state<="001";-- 进入写入状态(00 01 02 03)

                      when "100" =>state<="101";-- 进入读出状态(11 12)

                      when others=>state<="000";

                  end case;

            elsif state="001" then state<="010";--写地址

                                    en<='1';

                                    oe<='1';

                                    rw<='1';

                                    add<="00"&input;--“00”凑齐18位

                                                                                            output<=input;

                                    tempadd<=input;--临时存放地址,用于输出地址的八位

            elsif state="010" then state<="011";

                                    data<=input;-- 写入数据

                                                                                            output<=input;        

            elsif state="011" then state<="000";            

                                    en<='0';

                                      oe<='1';

                                      rw<='0';

                                      output<=tempadd(7 downto 0)&data(7 downto 0);-- 输出地址的八位和输出数据的八位

            elsif state="101" then state<="110";

                                    en<='1';

                                    oe<='1';

                                    rw<='1';

                                    add<="00"&input;--输入要读取的地址

                                                                                            output<=input;

            elsif state="110" then state<="101";

                                    en<='0';

                                      oe<='0';

                                      rw<='1';

            end if;

        end if;

    end if;

end process;

process (state)

      begin

        case state is                            --两位状态为,第一位表示0为写,1为读,第二位表示读或写第几个状态

                 when "000"=>seg<="01111110111111";    --00

                 when "001"=>seg<="01111110100001";    --01  

                 when "010"=>seg<="01111111011011";    --02

                 when "011"=>seg<="01111111110011";    --03

                 when "101"=>seg<="01000010100001";    --11

                 when "110"=>seg<="01000011011011";    --12

         when others=>

        end case;

      end process;

        实验结果

思考题:静态存储器的读、写时序各有什么特点?

                 答:1、静态RAM 用触发器作为存储单元存放1 和0,存取速度快,只要不掉电即可持续保持内容不变。2、与动态RAM相比,静态RAM的集成度较低,并且静态RAM无须考虑保持数据而设置的刷新电路,故扩展电路较简单。3、由于静态RAM是通过有源电路来保持存储器中的数据,因此,要消耗较多功率,价格也较高。

三、综合实验总结

  1. 实验难点

一开始并没有搞明白这个实验的目的是什么、最后要完成一个什么样的东西,通过反复审题和上网查阅资料终于搞懂了;

并且一开始也不是很清楚到底哪一排(列)应该显示数据还是地址还是随着拨码开关的状态实时变化。

  1. 心得体会

虽然该实验比实验一复杂,但在实验一的基础上来做实验二,感觉没那么难,有种举一反三的感觉,只是要多花点时间,多用点心。

  1. 个人分工

本人在此实验中负责所有工作,代码编写、硬件操作验证等均由本人完成,并且教会其他两位组员实验板的操作及代码原理。

实验三 控制器实验

一、目的与要求

  1. 编写VHDL程序,实现具有七条MIPS指令功能的控制器。
  2. 七条指令分别为:ADDU SUBU BNEZ JR OR LW SW。
  3. 7条指令格式及功能详见实验指导书。

二、实验正文

实验内容

        本实验通过用VHDL硬件描述语言设计指令控制器,帮助学生学习和掌握THCOMIPS指令系统的指令功能和指令格式。实验材料中提供了一个简单多周期控制器,该控制器视线了7条THCO MIPS指令功能,7条指令分别为ADDU SUBU BNEZ JR OR LW SW,具体功能和格式请参考实验指导书。

实验步骤

(1)现具有七条MIPS指令功能的控制器;

    (2)验板验证每条指令的信号正确。

    因为此实验是演示性实验,只需要自己编程出来的代码给老师演示一步步的操作,包括四个状态(PC ALU MEM REG)和五个周期(取指、译码、执行、访存、写回)的演示。实验板操作一次,就去对照一次代码,找到对应物理位置的LED灯,查看此时是亮或者灭。

部分代码

  1. ucf文件

NET "CLK" LOC = U9; #clk键

NET "RST" LOC = U10; #rst键

NET "clk0" LOC = B8; #11.0592MHz时钟晶振

NET "showCtrl" LOC = U11; #电路板右下方微动开关key0

NET "bZero_ctrl" LOC = V16; #电路板右下方微动开关key3

#电路板下方的16个拨码开关

NET "instructions[0]" LOC = J6;

NET "instructions[1]" LOC = J7;

NET "instructions[2]" LOC = K2;

NET "instructions[3]" LOC = K7;

NET "instructions[4]" LOC = M1;

NET "instructions[5]" LOC = N1;

NET "instructions[6]" LOC = N2;

NET "instructions[7]" LOC = R1;

NET "instructions[8]" LOC = R4;

NET "instructions[9]" LOC = U1;

NET "instructions[10]" LOC = V2;

NET "instructions[11]" LOC = V3;

NET "instructions[12]" LOC = V4;

NET "instructions[13]" LOC = U8;

NET "instructions[14]" LOC = R7;

NET "instructions[15]" LOC = T7;

#电路板上方的16个LED灯:

NET "light[0]" LOC = D10;

NET "light[1]" LOC = E10;

NET "light[2]" LOC = A11;

NET "light[3]" LOC = B11;

NET "light[4]" LOC = C11;

NET "light[5]" LOC = D11;

NET "light[6]" LOC = E11;

NET "light[7]" LOC = F11;

NET "light[8]" LOC = A12;

NET "light[9]" LOC = E12;

NET "light[10]" LOC = F12;

NET "light[11]" LOC = A13;

NET "light[12]" LOC = B13;

NET "light[13]" LOC = D13;

NET "light[14]" LOC = E13;

NET "light[15]" LOC = A14;

  1. vhdl文件

process(rst,clk)                  -- 控制的核心进程

          begin

                   if rst = '0' then

                           state <= instruction_fetch;

                           IorD <= '0';              -- 存储器地址来源:来自PC,即读出来的是指令

                           IRWrite <= '0';        -- 不写入IR寄存器

                           MemRead <= '0';             -- 不读存储器

                           MemtoReg <= "00";               -- 写入寄存器堆的数据来源:00:ALUOut  01:MDR

                           ALUOp <= "00";            -- 00 : ALU执行加操作               01:ALU执行减操作   10:指令的功能字段决定ALU操作

                           ALUSrcA <= '0';           -- 1:来自寄存器   0:来自PC

                           ALUSrcB <= "00";        -- "00":来自寄存器B       "01":常数1 "10":符号位扩展后IR的低16位

                           PCWrite <= '0';                -- 为1时改写PC

                           PCSource <= '0';        -- 0:直接来源于ALU输出 1:来源于ALUOut寄存器

                           RegDst <= "00";             -- 选择目的寄存器

                           RegWrite <= "000";        -- 写寄存器控制

                   elsif rising_edge(clk) then

                           case state is

                                    when instruction_fetch =>              --取指阶段: M -> IR , PC + 1 -> PC

                                            MemRead <= '1';             -- 从存储器中读出数据

                                            ALUSrcA <= '0';             -- ALU源操作数A:来自PC

                                         IorD <= '0';              -- 存储器地址来源:来自PC,即读出来的是指令

                                            ALUSrcB <= "01";         -- 常数1

                                            ALUOp <= "00";            -- ALU执行加操作

                                            PCWrite <= '1';                -- 改写PC的值

                                            PCSource <= '0';             -- 新的PC来源:直接来源于ALU的输出

                                            IRWrite <= '1';        -- 存储器的输出写入IR

                                            RegWrite <= "000";        -- 写寄存器控制:"000" 无

                                            state <= decode;              -- 进入解码状态

                                    when decode =>                               --解码阶段

                                            IRWrite <= '0';        -- 不写入IR

                                            MemRead <= '0';             -- 不从寄存器中读数据

                                            PCWrite <= '0';                -- PC不写

                                            ALUSrcA <= '0';             -- A

                                            ALUSrcB <= "10";         -- IR

                                            ALUOp <= "00";            -- 加

                                            state <= execute;

                                    when execute =>                              --执行阶段

                                            case instructions(15 downto 11) is

                                                    when "00100" =>             -- BEQZ:若寄存器rx的值为0,则跳转到目的地址immediate执行;否则顺序执行下一条指令

                                                             ALUSrcA <= '1';               -- PC

                                                             ALUOp <= "10";              -- 指令的功能字段决定ALU操作

                                                             PCSource <= '1';               -- 来源于ALUout寄存器

                                                            state <= instruction_fetch;

                                                    when "00110" =>              -- SLL

                                                             ALUSrcA <= '1';

                                                             ALUSrcB <= "00";

                                                             ALUOp <= "10";              -- 逻辑左移

                                                             state <= write_reg;

                                                    when "01101" =>              -- LI

                                                             ALUSrcA <= '1';               --A

                                                             ALUSrcB <= "10";           --0扩展后的IR

                                                             ALUOp <= "00";   

                                                             state <= write_reg;

                                                    when "01111" =>              -- MOVE

                                                             ALUSrcA <= '1';               -- A

                                                             ALUOp <= "10";              -- MOVE指令决定运算,即不运算

                                                             state <= write_reg;

                                                    when "10011" =>              -- LW 从内存读到寄存器

                                                             ALUSrcA <= '1';               -- A

                                                             ALUSrcB <= "10";           -- IR符号位扩展(立即数immediate)

                                                             ALUOp <= "00";              -- 加

                                                             state <= mem_control;

                                                    when "11011" =>              -- SW 从寄存器写入内存********

                                                             ALUSrcA <= '1';               -- A

                                                             ALUSrcB <= "10";           -- IR符号位扩展(立即数immediate)

                                                             ALUOp <= "00";              -- 加

                                                             state <= mem_control;

                                                    when "11100" =>

                                                             case instructions(1 downto 0) is

                                                                     when "01" =>                   -- ADDU

                                                                              ALUSrcA <= '1';     -- 来自寄存器A

                                                                              ALUSrcB <= "00"; -- 来自寄存器B

                                                                              ALUOp <= "00"; -- 加

                                                                     when "11" =>            -- SUBU

                                                                              ALUSrcA <= '1';     --来自寄存器A

                                                                              ALUSrcB <= "00"; --来自寄存器B

                                                                              ALUOp <= "01"; --减

                                                                     when others =>

                                                                              null;

                                                             end case;

                                                             state <= write_reg;

                                                    when "11101" =>

                                                             case instructions(4 downto 0) is

                                                                     when "01101" =>              -- OR

                                                                              ALUSrcA <= '1';     -- 来自寄存器A

                                                                              ALUSrcB <= "00"; -- 来自寄存器B

                                                                              ALUOp <= "10"; -- OR指令

                                                                              state <= write_reg;

                                                                     when "01111" =>              -- NOT

                                                                              ALUSrcA <= '1';

                                                                              ALUop <= "10"; -- NOT运算

                                                                              state <= write_reg;

                                                                     when "01110" =>              -- XOR

                                                                              ALUSrcA <= '1';

                                                                              ALUSrcB <= "00";

                                                                              ALUOp <= "10";

                                                                              state <= write_reg;

                                                                     when "00000" =>

                                                                              case instructions(7 downto 5) is

                                                                                      when "000" =>                   -- JR

                                                                                        ALUSrcA <= '1';

                                                                                        ALUOp <= "10";    -- 根据指令的功能字段决定操作

                                                                                        PCWrite <= '1';       -- 写PC

                                                                                        PCSource <= '0';     -- 数据:ALU输出

                                                                                              state <= instruction_fetch;

                                                                                      when others =>

                                                                                              null;

                                                                              end case;

                                                                     when others =>

                                                                              null;

                                                             end case;

                                                    when others =>

                                                             null;

                                            end case;

                                    when mem_control =>                      --访存阶段

                                            PCWrite <= '0';

                                            RegWrite <= "000";

                                            case instructions(15 downto 11) is

                                                    when "10011" =>              -- LW

                                                             MemRead <= '1';    -- 读寄存器

                                                             IorD <= '1';     -- 地址来源于ALUOut

                                                             state <= write_reg;

                                                    when "11011" =>           -- SW

                                                             MemRead <= '1';

                                                             IorD <= '1';

                                                             state <= write_reg;

                                                    when others =>

                                                             null;

                                            end case;

                                    when write_reg =>                             --写回阶段

                                            MemWrite <= '0';

                                            MemRead <= '0';

                                            case instructions(15 downto 11) is

                                                    when "01101" =>             -- LI

                                                             RegDst <= "00";     -- 选rx

                                                             RegWrite <= "001";-- 写

                                                             MemtoReg <= "00";  -- 来自ALUOut

                                                    when "01111" =>              -- MOVE

                                                             RegDst <= "00";     -- 选Rx

                                                             RegWrite <= "001";

                                                             MemtoReg <= "00";

                                                    when "10011" =>              -- LW

                                                             RegDst <= "10";     -- 目的寄存器为ry

                                                             RegWrite <= "001";-- 写

                                                             MemtoReg <= "01";  -- 数据来自于 MDR

                                                    when "11011" =>              -- SW

                                                             MemWrite <= '0';    -- 不写

                                                             IorD <= '0';     -- 来自PC

                                                    when "11100" =>

                                                             case instructions(1 downto 0) is

                                                                     when "01" =>  -- ADDU

                                                                              RegDst <= "01";          -- 指定寄存器rz

                                                                              RegWrite <= "001";       -- 将数据写入寄存器rz

                                                                              MemtoReg <= "00";          -- 数据来自ALUOut

                                                                     when "11" =>   -- SUBU

                                                                              RegDst <= "01";         

                                                                              RegWrite <= "001";

                                                                              MemtoReg <= "00";

                                                                     when others =>

                                                                              null;

                                                             end case;

                                                    when "11101" =>

                                                             case instructions(4 downto 0) is

                                                                     when "01101" =>   -- OR

                                                                              RegDst <= "00";         

                                                                              RegWrite <= "001";

                                                                              MemtoReg <= "00";

                                                                     when "01110" =>  -- XOR

                                                                              RegDst <= "00";

                                                                              RegWrite <= "001";

                                                                              MemtoReg <= "00";

                                                                     when "01111" =>  -- NOT6

                                                                              RegDst <= "00";

                                                                              RegWrite <= "001";

                                                                              MemtoReg <= "00";

                                                                     when others =>

                                                                              null;

                                                             end case;

                                                    when others =>

                                                             null;

                                            end case;

                                            state <= instruction_fetch;

                                    end case;

                           end if;

                   end process;

三、综合实验总结

  1. 实验难点

编程部分,ucf文件不好写,引脚的物理位置要对照之前的文件一个个去推理,写到一半才发现指导书上就有。控制信号太多,容易遗漏,四个状态和五个周期的转换也要注意对应的脉冲信号量是哪个;

操作部分,实验板的按键太过灵敏,按一下可能就跳过三四个状态,导致刚开始验证的时候以为是代码出错。

  1. 心得体会

实践出真知,脑子里的构思做出来不一定有想象中那么容易。

最重要的是,感谢老师和研究生学长学姐的耐心指导,没有他们的帮助,我们组还要走许多弯路,耗费许多精力和时间,由衷感激!

        3.     个人分工

                 本人在此实验中负责全部所有工作,代码编写、硬件操作验证等均由本人完成,并且教会其他两位组员实验板的操作及代码原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值