zoukankan      html  css  js  c++  java
  • 调试RSIC_CPU

    我们上一篇文章讲述了RISC_CPU的结构,但是要验证RISC_CPU能否正确工作,还需要一些外围电路来提供ROM(测试程序),RAM(装载数据)以及地址译码器。下面我们将一一做介绍。

    1、RISC_CPU寻址方式和指令系统

    RISC_CPU的一条指令有16位,其中前3位是指令opcode,后13位是地址ir_addr。
    指令.png
    操作码opcode有8种操作,由着8中操作可以实现任意的运算。

    • HLT,停机操作。
    • SKZ,如果累加器的输出accum为0,则跳过下一条语句,否则继续执行。
    • ADD,将累加器中的值与地址所指的ram中的数据相加,结果仍然送回累加器。
    • AND,将累加器中的值与地址所指的ram中的数据相与,结果仍然送回累加器。
    • XOR,将累加器中的值与地址所指的ram中的数据相异或,结果仍然送回累加器。
    • LDA,将指令中给出的地址的数据放入累加器。
    • STO,将累加器上的数据放入指令中给出的地址。
    • JMP,无条件跳转语句,跳转指令给出的目的地址,继续执行。

    RISC_CPU,是8位微处理器,一律采用直接寻址的方式,即数据总放在存储器中,寻址单元由指令直接给出。这是最简单的寻址方式。

    2、外围电路

    对RISC_CPU进行调试的话,需要外围电路提供ROM(测试程序),RAM(装载数据)以及地址译码器。

    地址译码器用于产生选通信号,选通ROM或RAM。

    module addr_decode (
                    addr,
                    ram_sel,
                    rom_sel
                    );
    
       input[12:0] addr;
       output ram_sel,rom_sel;
       reg rom_sel,ram_sel;
    
     always@(addr)
     begin
      casex(addr)
        13'b1_1xxx_xxxx_xxxx:{rom_sel,ram_sel}=2'b01;
        13'b0_xxxx_xxxx_xxxx:{rom_sel,ram_sel}=2'b10;
       13'b1_0xxx_xxxx_xxxx:{rom_sel,ram_sel}=2'b10;
       default:{rom_sel,ram_sel}=2'b00;
      endcase
    end
    
    endmodule
    

    13'h1FFF-----13'h1800 RAM
    13'h17FF-----13'h0000 ROM

    module ram_cpu (
                addr,
                  rd,
                  wr,
                  ena,
                  data    
                  );
    input[12:0] addr;
    input rd,wr,ena;
    inout[7:0] data;
    reg[7:0] memory_ram [13'h1fff:13'h1800];
    
     assign data=(rd&&ena)?memory_ram[addr]:8'bzzzzzzzz;
    
      always@(posedge wr)
      begin
       memory_ram[addr]<=data;
      end
    
    endmodule
    

    RAM用于存放的数据,可读可写。

     module rom_cpu (
                addr,
                rd,
                ena,
                data
                );
                
          input[12:0] addr;
          input rd,ena;
          output[7:0] data;
          wire[7:0] data;
         reg[7:0] memory_rom [13'h17ff:13'h0000]; 
    
         assign data=(ena&&rd)?memory_rom[addr]:8'bzzzzzzzz;
    
         endmodule               
    

    ROM用于装载测试程序。

    3、连接外围电路测试RSIC_CPU

    cpu_top.png

        /*`include "cpu.v"
        `include "ram_cpu"
        `include "rom_cpu"
         `include "addr_decode"*/
         `timescale 1ns/1ns
        //`define PERIOD 100
    
          module cpu_top;
               reg rst,clk;                                                         
               reg[(3*8):0] mnemonic;
               reg[12:0] PC_addr,IR_addr;
               wire[7:0] data;
               wire HALT,rd,wr,ram_sel,rom_sel;
               wire fetch;
               wire[12:0] addr;
               integer test;
               // wire[2:0] opcode;
               // wire[12:0]ir_addr,pc_addr;
    
             cpu cpu_t(  .clk(clk),
              .rst(rst),
              .data(data),
              .rd(rd),
              .wr(wr),
              .addr(addr),
              .HALT(HALT),
              .fetch(fetch));
    
                ram_cpu ram_cpu_t(.addr(addr),
                    .rd(rd),
                    .wr(wr),
                    .ena(ram_sel),
                    .data(data));  
                    
                rom_cpu rom_cpu_t(.addr(addr),
                    .rd(rd),
                    .ena(rom_sel),
                    .data(data));
                    
                addr_decode addr_decode_t(.addr(addr),
                            .ram_sel(ram_sel),
                            .rom_sel(rom_sel));     
    
                initial 
                   begin
                   clk=0;
                    $timeformat (-9,1,"ns",12);
                   display_debug_message;
                   asyn_rst;
                    //test1;
                   //test2;
                   //test3;
                    test4;
                  $finish;
                  end          
    
          task display_debug_message;
            begin
               $display("
    *********************");
               $display("load test");
               $display("***********************
    ");
            end
           endtask  
    
       task asyn_rst;
               begin
                 rst=1;
                 #10 
                 rst=0;
                 #40
                 rst=1;
                end 
             endtask                                                        
    
           /*task test1;
    begin
      test=0;
      disable MONITOR;
      $readmemb("C:/Users/XQ/Desktop/test_pro.txt",rom_cpu_t.memory_rom);
      $display("rom loaded successfully!");
      $readmemb("C:/Users/XQ/Desktop/test_dat.txt",ram_cpu_t.memory_ram);
      $display("ram loaded successfully!");
      #1 test=1;
      #10000;
      asyn_rst;
    end
    endtask
     
     always@(test)
       begin:MONITOR
    $display("
    ***running test1***");
    $display("
     TIME PC INSTRUCTION ADDR DATA");
    $display("  -------   ------   -----------   ------   ------");
    while (test==1)
    @(cpu_t.pc_addr)
    if((cpu_t.pc_addr%2==1)&&(cpu_t.fetch==1))
      begin
        #30 PC_addr<=cpu_t.pc_addr-1;
            IR_addr<=cpu_t.ir_addr;
        #130 $strobe("%t %h %s %h %h",$time,PC_addr,mnemonic,IR_addr,data);
      end
    end*/
    
    
      /*task test2;
    begin
      test=0;
      disable MONITOR;
      $readmemb("C:/Users/XQ/Desktop/test_pro.txt",rom_cpu_t.memory_rom);
      $display("rom loaded successfully!");
      $readmemb("C:/Users/XQ/Desktop/test_dat.txt",ram_cpu_t.memory_ram);
      $display("ram loaded successfully!");
      #1 test=1;
      #10000;
      asyn_rst;
    end
    endtask
    
     always@(test)
    begin:MONITOR
    $display("
    ***running test2***");
    $display("
      TIME      PC     INSTRUCTION   ADDR     DATA");
    $display("  -------   ------   -----------   ------   ------");
    while (test==1)
    @(cpu_t.pc_addr)
    if((cpu_t.pc_addr%2==1)&&(cpu_t.fetch==1))
      begin
        #30 PC_addr<=cpu_t.pc_addr-1;
            IR_addr<=cpu_t.ir_addr;
        #130 $strobe("%t %h %s %h %h",$time,PC_addr,mnemonic,IR_addr,data);
      end
     end*/
    
    /*task test3;
    begin
      test=0;
      disable MONITOR;
      $readmemb("C:/Users/XQ/Desktop/test_pro.txt",rom_cpu_t.memory_rom);
      $display("rom loaded successfully!");
      $readmemb("C:/Users/XQ/Desktop/test_dat.txt",ram_cpu_t.memory_ram);
      $display("ram loaded successfully!");
      #1 test=1;
      #1000000;
      asyn_rst;
    end
     endtask
    
     always@(test)
     begin:MONITOR
    $display("
    ***running test3***");
    $display("
      TIME      FN1      FN2    TEMP");
    $display("  -------    ------   ------  ----- ");
    while (test==1)
     begin
       wait (cpu_t.opcode==3'h1)
       $strobe("%t       %d      %d    %d",$time,ram_cpu_t.memory_ram[13'h1800],ram_cpu_t.memory_ram[13'h1801],ram_cpu_t.memory_ram[13'h1802]);
       wait (cpu_t.opcode!=3'h1);
     end
    end*/
    
     task test4;
      begin
      test=0;
      disable MONITOR;
      $readmemb("C:/Users/XQ/Desktop/test_pro.txt",rom_cpu_t.memory_rom);
      $display("rom loaded successfully!");
      $readmemb("C:/Users/XQ/Desktop/test_dat.txt",ram_cpu_t.memory_ram);
      $display("ram loaded successfully!");
      #1 test=1;
      #100000;
      asyn_rst;
    end
     endtask
    
     always@(test)
     begin:MONITOR
    $display("
    ***running test4***");
    $display("
      TIME      FN1      FN2    FN3    TEMP");
    $display("  -------    -------  ------- -----  ------");
    while (test==1)
     begin
       wait (cpu_t.opcode==3'h1)
       $strobe("%t       %d      %d    %d    %d",$time,ram_cpu_t.memory_ram[13'h1800],ram_cpu_t.memory_ram[13'h1801],ram_cpu_t.memory_ram[13'h1802],ram_cpu_t.memory_ram[13'h1804]);
       wait (cpu_t.opcode!=3'h1);
     end
    end
    
    always@(posedge HALT)
    begin
      #200
      $display("
    *********************");
      $display("**a HALT instruction was processed**");
      $display("*************************
    ");
    end
    
    always #20 clk=~clk;
    
    always@(cpu_t.opcode)
    begin
      case(cpu_t.opcode)
          3'b000:mnemonic="HLT";
          3'b001:mnemonic="SKZ";
          3'b010:mnemonic="ADD";
          3'b011:mnemonic="AND";
          3'b100:mnemonic="XOR";
          3'b101:mnemonic="LDA";
          3'b110:mnemonic="STO";
          3'b111:mnemonic="JMP";
          default:mnemonic="???";
        endcase
    end
    
    endmodule
    

    4、测试程序

    在这里我简单列出几个测试程序供大家调试应用。

    4.1 验证CPU逻辑功能的机器代码

    该测试程序用来验证RISC_CPU的opcode的正确性。
    ROM中的程序

     @0000
     111_00000 //00  begin:  JMP TST_JMP
     0011_1100 
     000_00000 //02          HLT  //JMP did not work at all
     0000_0000
     000_00000 //04          HLT //JMP did not load PC,it skipped
     0000_0000
     101_11000 //06 JMP_OK:  LDA DATA_1
     0000_0000
     001_00000 //08          SKZ
     0000_0000
     000_00000 //0a          HLT //SKZ or LDA did not work
     0000_0000
     101_11000 //0c          LDA DATA_2
     0000_0001
     001_00000 //0e          SKZ
     0000_0000
    111_00000 //10          JMP SKZ_OK
     0001_0100
     000_00000 //12          HLT //SKZ or LDA did not work
     0000_0000
    110_11000 //14 SKZ_OK:  STO TEMP //store non-zero vaule in TEMP
    0000_0010
    101_11000 //16          LDA DATA_1
     0000_0000
    110_11000 //18          STO TEMP //store zero vaule in TEMP
     0000_0010
     101_11000 //1a          LDA TEMP
     0000_0010
     001_00000 //1c          SKZ //check to see if STO worked
     0000_0000
     000_00000 //1e          HLT //STO did not work
     0000_0000
     100_11000 //20          XOR DATA_2
     0000_0001
     001_00000 //22          SKZ //check to see XOR worked
     0000_0000
     111_00000 //24          JMP XOR_OK
     0010_1000
     000_00000 //26          HLT //XOR did not work at all
     0000_0000
     100_11000 //28 XOR_OK:  XOR DATA_2
     0000_0001
     001_00000 //2a          SKZ
    0000_0000
    000_00000 //2c          HLT //XOR did not switch all bits
    0000_0000
    000_00000 //2e END:     HLT //CONGRATULATIONS-TEST1 PASSED!
     0000_0000
     111_00000 //30          JMP BEGIN //run test again
     0000_0000
    
       @3c
       111_00000 //3c TST_JMP: JMP JMP_OK
       0000_0110
       000_00000 //3e          HLT //JMP is broken
    

    RAM中的数据

     @1800
     00000000  //1800 DATA_1: //constant 00(hex)
     11111111  //1801 DATA_2: //constant FF(hex)
     10101010  //1802 TEMP:   //variable - starts with AA(hex)
    
    4.2 验证CPU的高级指令集

    ROM中存放的程序

        @0000
        101_11000 //00  begin: LDA DATA_2
        0000_0001  
        011_11000 //02         AND DATA_3
        0000_0010
        100_11000 //04         XOR DATA_2
         0000_0001
         001_00000 //06         SKZ
         0000_0000
         000_00000 //08         HLT         //AND doesn't work
         0000_0000
         010_11000 //0a         ADD DATA_1
         0000_0000
         001_00000 //0c         SKZ
         0000_0000
         111_00000 //0e         JMP          //ADD_OK
         0001_0010
         000_00000 //10         HLT          //ADD doesn't work
         0000_0000
         100_11000 //12  ADD_OK:XOR DATA_3
          0000_0010
         010_11000 //14         ADD DATA_1  //FE plus 1 makes FF
         0000_0000 
         110_11000 //16         STO TEMP
          0000_0011
         101_11000 //18         LDA DATA_1
         0000_0000
         010_11000 //1a         ADD TEMP   //FF plus 1 makes 100(hex)
         0000_0011
         001_00000 //1c         SKZ
         0000_0000
         000_00000 //1e         HLT        //ADD doesn't work
         0000_0000
         000_00000 //20  END:   HLT        //congratulations test passed
         0000_0000 
         111_00000 //22  JMP begin        //run test again
         0000_0000
    

    RAM中存放的数据

      @1800
       00000001  //1800 DATA_1: //constant 01(hex)
       10101010  //1801 DATA_2: //constant AA(hex)
       11111111  //1802 DATA_3: //constant FF(hex)
       00000000  //1803 TEMP:   //variable - starts with 00(hex)
    
    4.3 验证CPU的功能-Fibonacci序列

    所谓Fibonacc序列,就是后一个数是前两个数相加的和,0、1、1、2、3、5、8、13、21、34......
    Fibonacci.png
    (1)将FN2放入TEMP
    (2)将FN1+FN2的结果放入FN2
    (3)将TEMP放入FN1
    (4)将FN1与LIMIT做异或操作,决定循环是否继续进行

    ROM中的指令

        @0000
         101_11000 //00  LOOP: LDA FN2  //load value in FN2 into accum
          0000_0001
          110_11000 //02        STO TEMP //store accum in TEMP
          0000_0010
          010_11000 //04        ADD FN1  
          0000_0000
          110_11000 //06        STO FN2
          0000_0001
          101_11000 //08        LDA TEMP 
          0000_0010
          110_11000 //0a        STO FN1
           0000_0000
           100_11000 //0c        XOR LIMIT
           0000_0011
           001_00000 //0e        SKZ
           0000_0000
           111_00000 //10        JMP LOOP
           0000_0000
          000_00000 //12  DONE: HLT
          0000_0000
    

    RAM中的数据

        @1800
        00000001  //1800 FN1
        00000000  //1801 FN2
        00000000  //1802 TEMP
        10010000  //1803 LIMIT
    
    4.4 验证CPU的功能-阶乘

    此程序的功能就是计算5!
    Factorial.png
    其中:

    • FN2用于计算累加的次数
    • FN3用于计算是否达到LIMIT
    • TEMP用于存放n!的结果

    ROM中的程序

       @00
       101_11000  //00   LOOP1: LDA TEMP
       0000_0100
       010_11000  //02   	  ADD FN1
       0000_0000
       110_11000  //04    	  STO TEMP
        0000_0100
       101_11000  //06	  LDA FN2
       0000_0001
       010_11000  //08	  ADD DATA
       0000_0101
       110_11000  //0a 	  STO FN2
       0000_0001
       100_11000  //0c	  XOR FN3
       0000_0010
       001_00000  //0e	    SKZ
       0000_0000
       111_00000  //10	 JMP LOOP1
       0000_0000
       101_11000  //12	 LDA FN3
         0000_0010
         010_11000  //14	 ADD DATA
         0000_0101
        110_11000  //16	 STO FN3
        0000_0010
        101_11000  //18	 LDA DATA
         0000_0101
        110_11000  //1a	 STO FN2
         0000_0001
        101_11000  //1c	 LDA TEMP
        0000_0100
        110_11000  //1e	 STO FN1
        0000_0000
        101_11000  //20	 LDA FN3
        0000_0010
        100_11000  //22	 XOR LIMIT
        0000_0011
        001_00000  //24	   SKZ
        0000_0000
        111_00000  //26	 JMP LOOP1
        0000_0000
        000_00000  //28	 DONE: HLT
        0000_0000
    

    RAM中的数据

         @00
           0000_0001	//1800 FN1	
           0000_0001	//1801 FN2
           0000_0010	//1802 FN3
           0000_0110	//1803 LIMIT
           0000_0001	//1804 TEMP
           0000_0001	//1805 DATA
  • 相关阅读:
    (jmeter笔记)jmeter远程启用服务器(分布式)
    (jmeter笔记)jmeter打印日志
    (jmeter笔记)Jmeter正则表达式提取器获取Response hearders
    css3实现好看的边框效果
    简单递归写侧边菜单栏
    css3的transform-origin配合scale,控制动画,实现各种hover效果
    浅谈jQuery的promise
    tips07-encodeURI()的使用
    weui 的使用方法
    git 合并分支的时候会遇到的问题
  • 原文地址:https://www.cnblogs.com/xuqing125/p/8516921.html
Copyright © 2011-2022 走看看