精华内容
下载资源
问答
  • 1.lw,sw指令格式及功能 ...lw指令和sw指令需要DataMem(数据存储器)来取数据或存数据。 执行过程: lw: 从数存中取数据写入寄存器,rega提供数存单元地址(源),regc提供寄存器地址(目的)。 ①IF模块将

    1.lw,sw指令格式及功能

    指令 [31:26] [25:21] [20:16] [15:0] 意义
    lw 100011 rs rt offset 从数存(数据存储器)中取数据写进寄存器
    sw 101011 rs rt offset 将寄存器中的值写入数存

    2.所需模块框图及指令执行过程

    在这里插入图片描述
           lw指令和sw指令需要DataMem(数据存储器)来取数据或存数据。

           执行过程:
           lw:
           从数存中取数据写入寄存器,rega提供数存单元地址(源),regc提供寄存器地址(目的)。
           ①IF模块将指令地址pc和片选信号romCe送入指存InstMem,存InstMem中取出数据由data脚送入ID模块的inst脚。
           ②ID将送入的inst进行译码,对于lw指令,将指令中的rs为送入regaAddr,连同regaRd读信号送入寄存器堆RegFile,读出regaData,送入ID模块的regaData_i。regaData_i里的数据加上指令中(经符号位扩展的)offset位,即regaData_i+offset,regaData_i+offset表示的就是要取的数据(在数存中)的地址。将regaData_i+offset送入ID的regaData,将指令中的rt位送入regcAddr。将ID中的regaData,regcAddr和regcWr分别送入EX模块的regaData,regcAddr_i和regcWr_i。
           ③EX模块的regaData作为memAddr送入内存MEM,regcAddr_i和regcWr_i作为regcAddr和regcWr送入MEM。
           ④MEM将送入的memAddr给要送出的memAddr(这里纠正框图中的一个错误,送入的memAddr应改为memAddr_i,modelsim中不能有命名相同的参数或变量。所以在这里将memAddr_i和memAddr分别称为要送入的memAddr和要送出的memAddr,下文也是一样,不再说明),将要取的数据地址memAddr和片选信号memCe送入数存DataMem,读取数据,从rdData送入MEM。
           ⑤MEM将rdData作为regData,将regcAddr作为regAddr,将regcWr作为regWr,然后将regData,regAddr和regWr送入regFile,将数据regData写进地址为regAddr的寄存器中。lw指令执行完毕。

           sw:
           将寄存器中的数据写入数存,rega提供数存单元地址(目的),regb提供寄存器地址(源)。
           ①IF模块将指令地址pc和片选信号romCe送入指存InstMem,存InstMem中取出数据由data脚送入ID模块的inst脚。
           ②ID将送入的inst进行译码,对于sw指令,将指令中的rs位送入regaAddr。指令中的rt位送入regbAddr,将regbAddr、regaAddr、regaRd,regbRd送入RegFile,找到regbData和regaData送入ID的regbData_i和regaData_i。将regaData_i加上(经符号位扩展)的offset,并送入regaData。此时regaData中保存的就是要写入的数据在数存中的地址,regbData保存的就是要写入数存中的数据。将regaData和regbData分别送入EX的regaData和regbData。
           ③EX中,将regaData作为memAddr,regbData作为memData,分别送入MEM中的memAddr和memData。
           ④MEM将memData作为wtData,连通memAddr,memWr和memCe分别送入DataMem中的wtData、addr、we和ce,将数据写进DataMem,sw指令执行完毕。

    3.代码

           ①define.v

    
    `define RstEnable        1'b0
    `define RstDisable       1'b1
    
    `define RomDisable       1'b0
    `define RomEnable        1'b1
    
    `define RamWrite         1'b1
    `define RamUnWrite       1'b0
    `define RamEnable        1'b1
    `define RamDisable       1'b0
    
    `define Valid            1'b1
    `define Invalid          1'b0
    
    `define Zero             32'h00000000
    `define nop              6'b001101
    
    `define Inst_lw          6'b100011
    `define Inst_sw          6'b101011
    
    `define Lw              6'b001100
    `define Sw              6'b001101
    

           ②IF.v

    
    `include "define.v"
    
    module IF(
    
        input wire clk,
        input wire rst,
        output reg [31:0] pc,
        output reg romCe,
        input wire [31:0] jAddr,
        input wire jCe
        
    
    );
    
        always@(*)
            if(rst == `RstEnable)
               romCe = `RomDisable;
            else
                romCe = `RomEnable;
    
         always@(posedge clk)
            if(romCe == `RomDisable)
                pc = `Zero;
            else if(jCe == `Valid)
                pc = jAddr;
            else
                pc = pc+4;
    
    endmodule
    

           ③InstMem.v

    
    `include "define.v"
    
    module InstMem(
    
        input wire ce,
        input wire [31:0] addr,
        output reg [31:0] data
    );
    
        reg [31:0] instmem [1023:0];
        always@(*)
            if(ce == `RomDisable)
                data = `Zero;
            else
                data = instmem[addr[11:2]];
        initial
            begin
                instmem[0] = 32'h8E1F0001;  //lw
                instmem[1] = 32'hAC890000;  //sw
            end
    
    endmodule
    
    

           ④ID.v

    
    `include "define.v"
    
    module ID(
    
        input wire rst,
        input wire [31:0] inst,
        input wire [31:0] regaData_i,
        input wire [31:0] regbData_i,
        input wire [31:0] pc_i,
        output reg [5:0] op,
        output reg [31:0] regaData,
        output reg [31:0] regbData,
        output reg regcWr,
        output reg [31:0] regcAddr,
        output reg regaRd,
        output reg [31:0] regaAddr,
        output reg regbRd,
        output reg [31:0] regbAddr,
        output reg [31:0] jAddr,
        output reg jCe,
        output wire [31:0] pc
    );
    
        wire [31:0] npc = pc + 4;
        wire [5:0] Inst_op = inst[31:26];
        wire [5:0] func = inst[5:0];
        reg [31:0] imm;
    
    //    assign pc = pc_i;
    
    
        always@(*)
            if(rst == `RstEnable)
                begin
                    op = `nop;
                    regaRd = `Invalid;
                    regbRd = `Invalid;
                    regcWr = `Invalid;
                    regaAddr = `Zero;
                    regbAddr = `Zero;
                    regcAddr = `Zero;
                    imm = `Zero;
                    jCe = `Invalid;
                    jAddr = `Zero;
                end
            else
                begin
                    jCe = `Invalid;
                    jAddr = `Zero;
                case(Inst_op)
                    `Inst_lw:
                        begin
                            op = `Lw;
                            regaRd = `Valid;
                            regbRd = `Invalid;
                            regcWr = `Valid;
                            regaAddr = inst[25:21];
                            regbAddr = `Zero;
                            regcAddr = inst[20:16];
                            imm = {{16{inst[15]}},inst[15:0]};
                        end
                    `Inst_sw:
                        begin
                            op = `Sw;
                            regaRd = `Valid;
                            regbRd = `Valid;
                            regcWr = `Invalid;
                            regaAddr = inst[25:21];
                            regbAddr = inst[20:16];
                            regcAddr = `Zero;
                            imm = {{16{inst[15]}},inst[15:0]};
                        end
                endcase
                end
        always@(*)
            if(rst == `RstEnable)
                regaData = `Zero;
            else if(op == `Lw || op == `Sw)
                regaData = regaData_i + imm;
            else if(regaRd == `Valid)
                regaData = regaData_i;
            else
                regaData = imm;
    
        always@(*)
            if(rst == `RstEnable)
                regbData = `Zero;
            else if(regbRd == `Valid)
                regbData = regbData_i;
            else
                regbData = imm;
    endmodule
    

           ⑤EX.v

    `include "define.v"
    
    module EX(
    
        input rst,
        input wire [5:0] op_out,
        input wire [5:0] op_i,
    
    //    input wire [31:0] pc_i,
        input wire [31:0] regaData,
        input wire [31:0] regbData,
        output reg [31:0] regcData,
        
        input wire regcWr_i,
        input wire [4:0] regcAddr_i,
        output wire regcWr,
        output wire [4:0] regcAddr,
        output wire [31:0] memAddr,
        output wire [31:0] memData,
    
    //HiLo
        output reg [31:0] wHiData, //lw,sw
        output reg [31:0] wLoData,
        output wire [31:0] rHiData,
        output wire [31:0] rLoData,
        output reg whi,
        output reg wlo
        
    
    );
    
        assign op_out = op_i;
        assign memAddr = regaData;
        assign memData = regbData;
    
        assign regcWr = regcWr_i;
        assign regcAddr = regcAddr_i;
    endmodule
    
    

           ⑥MEM.v

    `include "define.v"
    
    module MEM(
        
        input wire rst,
        input wire [5:0] op,
        input wire [31:0] regcData,
        input wire [4:0] regcAddr,
        input wire regcWr,
        input wire [31:0] memAddr_i,
        input wire [31:0] memData,
        input wire [31:0] rdData,
        
        output wire [31:0] regData,
        output wire [4:0] regAddr,
        output wire regWr,
        output wire [31:0] memAddr,
        output reg [31:0] wtData,
        output reg memWr,
        output reg memCe
    );
    
        assign regData = (op == `Lw) ? rdData : regcData;
        assign regAddr = regcAddr;
        assign regWr = regcWr;
        assign memAddr = memAddr_i;
    
        always@(*)
            if(rst == `RstEnable)
                begin
                    wtData = `Zero;
                    memWr = `RamUnWrite;
                    memCe = `RamDisable;
                end
            else
                case(op)
                    `Lw:
                        begin
                            wtData = `Zero;
                            memWr = `RamUnWrite;//read
                            memCe = `RamEnable;
                        end
                    `Sw:
                        begin
                            wtData = memData;
                            memWr = `RamWrite;//write
                            memCe = `RamEnable;
                        end
                    default:
                        begin
                            wtData = `Zero;
                            memWr = `RamUnWrite;
                            memCe = `RamDisable;
                        end
                endcase
    endmodule
    

           ⑦DataMem.v

    
    `include "define.v"
    module DataMem(
        input wire clk,
        input wire ce,
        input wire we,
        input wire [31:0] wtData,
        input wire [31:0] memAddr,
        output reg [31:0] rdData
    );
        reg [31:0] data [31:0];  
        always@(*)
            if(ce == `RamDisable)
                rdData = `Zero;
            else rdData = data[memAddr[11:2]];
        always@(posedge clk)
            if(ce == `RamEnable && we == `RamWrite)
                data[memAddr[11:2]] = wtData;
            else ;
        initial
            begin
                data [1] = 32'h0000001A; //lw
            end
    endmodule
    

           ⑧RegFile.v

    
    `include "define.v"
    
    module RegFile(
    
        input wire clk,
        input wire rst,
        input wire we,
        input wire [4:0] wAddr,
        input wire [31:0] wData,
        input wire regaRd,
        input wire regbRd,
        input wire [4:0] regaAddr,
        input wire [4:0] regbAddr,
        output reg [31:0] regaData,
        output reg [31:0] regbData
    );
    
        reg [31:0] reg32 [31 : 0];    
        always@(*)
            if(rst == `RstEnable)
                regaData = `Zero;
            else if(regaAddr == `Zero)
                regaData = `Zero;
            else
                regaData = reg32[regaAddr];
        always@(*)
            if(rst == `RstEnable)          
                regbData = `Zero;
            else if(regbAddr == `Zero)
                regbData = `Zero;
            else
                regbData = reg32[regbAddr];
        always@(posedge clk)
            if(rst != `RstEnable)
                if((we == `Valid) && (wAddr != `Zero))
                    reg32[wAddr] = wData;
            else ;  
        initial
            begin
                reg32[4] = 32'h00000010; //sw
                reg32[9] = 32'h000000FF; //sw   
                reg32[16] = 32'h00000004; //lw
            end
    
       
    endmodule 
    

           ⑨MIPS.v

    `include "define.v"
    module MIPS(
        input wire clk,
        input wire rst,
        input wire [31:0] instruction,
        output wire romCe,
        output wire [31:0] instAddr
    );
        wire [31:0] regaData_regFile, regbData_regFile;
        wire [31:0] regaData_id, regbData_id; 
        wire [31:0] regcData_ex;
        wire [5:0] op;    
        wire regaRd, regbRd;
        wire [4:0] regaAddr, regbAddr;
        wire regcWr_id, regcWr_ex;
        wire [4:0] regcAddr_id, regcAddr_ex;
        wire [31:0] jAddr;
        wire jCe;
    
        wire [5:0] op_ex;
        wire [31:0] memAddr_ex,memData_ex;//lw and sw
        wire [31:0] rdData,wtData;
        wire [31:0] memAddr;
        wire [4:0] regAddr_mem;
        wire [31:0] regData_mem;
        wire memWr,memCe;
        wire regWr_mem;
    
        wire wlo,whi;//hilo
        wire [31:0] wLoData,wHiData;
        wire [31:0] rLoData,rHiData;
    
        IF if0(
            .clk(clk),
            .rst(rst),
            .jAddr(jAddr),
            .jCe(jCe),
            .romCe(romCe), 
            .pc(instAddr)
        );
        ID id0(
            .rst(rst),        
            .inst(instruction),
            .regaData_i(regaData_regFile),
            .regbData_i(regbData_regFile),
            .pc(instAddr),
            .op(op),
            .regaData(regaData_id),
            .regbData(regbData_id),
            .regaRd(regaRd),
            .regbRd(regbRd),
            .regaAddr(regaAddr),
            .regbAddr(regbAddr),
            .regcWr(regcWr_id),
            .regcAddr(regcAddr_id),
            .jAddr(jAddr),
            .jCe(jCe)
        );
        EX ex0(
            .rst(rst),
            .op_i(op),        
            .regaData(regaData_id),
            .regbData(regbData_id),
            .regcWr_i(regcWr_id),
            .regcAddr_i(regcAddr_id),
            .rHiData(rHiData),
            .rLoData(rLoData),
            .regcData(regcData_ex),//out
            .regcWr(regcWr_ex),
            .regcAddr(regcAddr_ex),
            .op_out(op_ex),//lw and sw
            .memAddr(memAddr_ex),
            .memData(memData_ex),
            .whi(whi),
            .wlo(wlo),
            .wHiData(wHiData),
            .wLoData(wLoData)
        );    
        MEM mem0(
            .rst(rst),
            .op(op_ex),
            .regcData(regcData_ex),
            .regcAddr(regcAddr_ex),
            .regcWr(regcWr_ex),
            .memAddr_i(memAddr_ex),
            .memData(memData_ex),
            .rdData(rdData),
            .regData(regData_mem),
            .regAddr(regAddr_mem),
            .regWr(regWr_mem),
            .memAddr(memAddr),
            .wtData(wtData),
            .memWr(memWr),
            .memCe(memCe)
        );
        DataMem datamem0(
            .clk(clk),
            .ce(memCe),
            .we(memWr),
            .wtData(wtData),
            .memAddr(memAddr),
            .rdData(rdData)
        );
        RegFile regfile0(
            .clk(clk),
            .rst(rst),
            .we(regWr_mem),
            .wAddr(regAddr_mem),
            .wData(regData_mem),
            .regaRd(regaRd),
            .regbRd(regbRd),
            .regaAddr(regaAddr),
            .regbAddr(regbAddr),
            .regaData(regaData_regFile),
            .regbData(regbData_regFile)
        );
    endmodule
    

           ⑩SoC.v

    module SoC(
        input wire clk,
        input wire rst
    );
        wire [31:0] instAddr;
        wire [31:0] instruction;
        wire romCe;    
        MIPS mips0(
            .clk(clk),
            .rst(rst),
            .instruction(instruction),
            .instAddr(instAddr),
            .romCe(romCe)
        );    
        InstMem instrom0(
            .ce(romCe),
            .addr(instAddr),
            .data(instruction)
        );
    endmodule
    
    
    

           11. soc_tb.v

    `include "define.v"
    module soc_tb;
        reg clk;
        reg rst;
        initial
          begin
            clk = 0;
            rst = `RstEnable;
            #100
            rst = `RstDisable;
            #10000 $stop;      //run to 10000,simulate stop(Zan ting)       
          end
        always #10 clk = ~ clk;
        SoC soc0(
            .clk(clk), 
            .rst(rst)
        );
    endmodule
    
    
    

    4.仿真图

           RegFile里的数据:

                reg32[4] = 32'h00000010; //sw
                reg32[9] = 32'h000000FF; //sw   
                reg32[16] = 32'h00000004; //lw
    

           DataMem里的数据:

                data [1] = 32'h0000001A; //lw
    

           我的lw指令和sw指令:
           lw:8E1F0001,其二进制为100011 10000 11111 0000 0000 0000 0001。
           sw:AC890000,其二进制为101011 00100 01001 0000000000000000。
           lw指令将数存地址为32’h00000004(reg32[16])中的数据32’h0000001A(data[1])写入到RegFile中地址为5’b11111的寄存器中(即r31寄存器)。

           sw指令将RegFile中的数据32’h000000FF(reg32[9])写到数存的data[4]中,之所以是data[4],是因为RegFile的reg32[4]中的数据是32’h00000010,即写入到数存的第16个字节中,而data是宽度为32位的寄存器,一个字节8位,data的每位都是4个字节,数存的第16个字节刚好是data的第4位,即data[4]。仿真图如下:
    在这里插入图片描述
           因为读出是组合逻辑,任意时间都能看到数据,写入是时序逻辑只有时钟上升沿才能写入到寄存器,所以数存中的数据32’h0000001a在lw指令的下一周期才被写入RegFile的31号寄存器reg32[31]。和lw一样,需要在sw的下一个周期才能从RegFile读出写入的数据32’b000000FF,写入的地址就是data[4]。

    展开全文
  • 在实际cpu的运行过程中,由于CPU存在分支预测功能,beq指令的周期不是固定的。 比如有8级流水的CPU,beq的指令周期有1-8个时钟周期(还是7个?目前我调试的时候发现最多的是7个)。 另外,即使对于lw指令,其指令...

    现代CPU由于存在多级流水线,对于分支处理又存在分支预测功能,因此在实际cpu的运行过程中,beq指令的周期不是固定的。
    另外,即使对于其他指令,比如lw指令,其指令周期也不是固定的。取决于该指令跟后面的指令有没有依赖关系。在这里插入图片描述 使用2周期的那些lw指令的bne指令都是需要用到前一条lw指令的结果,所以必须等前一条完成之后才能执行。比如 lw a0,1540(t1)与bne a0,x0,-1,bne指令必须等 a0 的 load 结果出来之后才能开始执行。lw 本身都是4周期的,如果前后没有依赖关系就可以pipeline起来,看起来就是一个周期完成一样。比如图中前面那些1个周期的lw指令都是没有依赖关系的。另外,lw 周期数跟具体实现有关系,最少2周期,如果存储接口插入了等待周期会更长,具体到某个指令多少得分析微架构。所以说,并不能直接从代码段知道一个函数的实际运行时间,需要实际运行看看。
    执行一个小程序进行测试(测试cpu为8级流水线),从log中获知一共使用了31个不同的指令。指令和指令次数为:
    在这里插入图片描述

    1, 跳转和返回指令

    jal指令:

    即使没有依赖关系,也是最少5周期:本测试一共有2983个jal指令,其指令周期和次数有:
    在这里插入图片描述
    可以看出,jalr指令的大部分的指令周期是5。

    jalr指令:

    jalr指令一共有2279个jalr指令,其指令周期和次数有:
    在这里插入图片描述
    可以看出,jalr指令的大部分的指令周期是5。

    mret指令

    mret指令,一共79个:
    在这里插入图片描述
    大部分为9个周期。

    2, add和addi指令

    add指令,一共4129个,1个周期和4个周期大约各占一半。
    addi指令,一共22708个,大部分是1个周期。
    伪代码中的li指令,会转换为addi指令来执行。比如li a5,4指令,会转换为addr a5,x0,4。

    3, load和store指令

    在这里插入图片描述

    lw指令

    lw指令,一共24338个,1个周期和2个周期的大约各占一半。
    在这里插入图片描述

    lbu指令

    lbu指令,一共1572个:
    在这里插入图片描述
    可以看出,lbu指令的时间周期并没有比lw指令少。

    sw指令

    sw指令,一共13636个,大部分需要1个时钟周期。
    在这里插入图片描述

    sb和sh指令

    sb和sh指令与sw指令类似,大部分需要1个时钟周期。

    4,分支预测指令

    在这里插入图片描述

    bne指令

    bne指令,一共5389个:
    在这里插入图片描述
    66%是7个周期。
    有1次15 cycle是因为后面来了一个中断,需要跳转到中断服务函数。
    有11次用了13个cycle, 主要就是分支开销, 没有指令预测, 结果遇到分支跳转,开销就大;一般跳转后面的时间长, 很大可能都是分支跳转的开销。开销最大的情况是跳转后 又遇到 cache miss; 计算这个开销是 从取指令到提交的流水线级数+cache miss的取指时间。
    总结:所以我们在写代码的时候,最好把运行概率大的那个分支写到if中。

    bge,begu,blt指令

    这三个指令大部分都是6个周期。可以看到,分支跳转指令是比较耗时的。

    5, 与状态寄存器有关的指令

    csrrs,csrrw,csrrwi,这些指令在实际测试中一般耗费4个时钟周期。

    6,nop指令

    nop指令,一共1060个:
    在这里插入图片描述

    7,其他指令

    大部分都是1个时钟周期。

    展开全文
  • MIPS 指令

    万次阅读 2017-05-10 14:53:27
    功能 应用实例 LB 从存储器中读取一个字节数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字数据到寄存器中 LH R1, 0(R2) LW ...

    MIPS 指令

     

    指令

    功能

    应用实例

    LB

    从存储器中读取一个字节的数据到寄存器中

    LB R1, 0(R2)

    LH

    从存储器中读取半个字的数据到寄存器中

    LH R1, 0(R2)

    LW

    从存储器中读取一个字的数据到寄存器中

    LW R1, 0(R2)

    LD

    从存储器中读取双字的数据到寄存器中

    LD R1, 0(R2)

    L.S

    从存储器中读取单精度浮点数到寄存器中

    L.S R1, 0(R2)

    L.D

    从存储器中读取双精度浮点数到寄存器中

    L.D R1, 0(R2)

    LBU

    功能与LB指令相同,但读出的是不带符号的数据

    LBU R1, 0(R2)

    LHU

    功能与LH指令相同,但读出的是不带符号的数据

    LHU R1, 0(R2)

    LWU

    功能与LW指令相同,但读出的是不带符号的数据

    LWU R1, 0(R2)

    SB

    把一个字节的数据从寄存器存储到存储器中

    SB R1, 0(R2)

    SH

    把半个字节的数据从寄存器存储到存储器中

    SH R1,0(R2)

    SW

    把一个字的数据从寄存器存储到存储器中

    SW R1, 0(R2)

    SD

    把两个字节的数据从寄存器存储到存储器中

    SD R1, 0(R2)

    S.S

    把单精度浮点数从寄存器存储到存储器中

    S.S R1, 0(R2)

    S.D

    把双精度数据从存储器存储到存储器中

    S.D R1, 0(R2)

    DADD

    把两个定点寄存器的内容相加,也就是定点加

    DADD R1,R2,R3

    DADDI

    把一个寄存器的内容加上一个立即数

    DADDI R1,R2,#3

    DADDU

    不带符号的加

    DADDU R1,R2,R3

    DADDIU

    把一个寄存器的内容加上一个无符号的立即数

    DADDIU R1,R2,#3

    ADD.S

    把一个单精度浮点数加上一个双精度浮点数,结果是单精度浮点数

    ADD.S F0,F1,F2

    ADD.D

    把一个双精度浮点数加上一个单精度浮点数,结果是双精度浮点数

    ADD.D F0,F1,F2

    ADD.PS

    两个单精度浮点数相加,结果是单精度浮点数

    ADD.PS F0,F1,F2

    DSUB

    两个寄存器的内容相减,也就是定点数的减

    DSUB R1,R2,R3

    DSUBU

    不带符号的减

    DSUBU R1,R2,R3

    SUB.S

    一个双精度浮点数减去一个单精度浮点数,结果为单精度

    SUB.S F1,F2,F3

    SUB.D

    一个双精度浮点数减去一个单精度浮点数,结果为双精度浮点数

    SUB.D F1,F2,F3

    SUB.PS

    两个单精度浮点数相减

    SUB.SP F1,F2,F3

    DDIV

    两个定点寄存器的内容相除,也就是定点除

    DDIV R1,R2,R3

    DDIVU

    不带符号的除法运算

    DDIVU R1,R2,R3

    DIV.S

    一个双精度浮点数除以一个单精度浮点数,结果为单精度浮点数

    DIV.S F1,F2,F3

    DIV.D

    一个双精度浮点数除以一个单精度浮点数,结果为双精度浮点数

    DIV.D F1,F2,F3

    DIV.PS

    两个单精度浮点数相除,结果为单精度

    DIV.PS F1,F2,F3

    DMUL

    两个定点寄存器的内容相乘,也就是定点乘

    DMUL R1,R2,R3

    DMULU

    不带符号的乘法运算

    DMULU R1,R2,R3

    MUL.S

    一个双精度浮点数乘以一个单精度浮点数,结果为单精度浮点数

    DMUL.S F1,F2,F3

    MUL.D

    一个双精度浮点数乘以一个单精度浮点数,结果为双精度浮点数

    DMUL.D F1,F2,F3

    MUL.PS

    两个单精度浮点数相乘,结果为单精度浮点数

    DMUL.PS F1,F2,F3

    AND

    与运算,两个寄存器中的内容相与

    ANDR1,R2,R3

    ANDI

    一个寄存器中的内容与一个立即数相与

    ANDIR1,R2,#3

    OR

    或运算,两个寄存器中的内容相或

    ORR1,R2,R3

    ORI

    一个寄存器中的内容与一个立即数相或

    ORIR1,R2,#3

    XOR

    异或运算,两个寄存器中的内容相异或

    XORR1,R2,R3

    XORI

    一个寄存器中的内容与一个立即数异或

    XORIR1,R2,#3

    BEQZ

    条件转移指令,当寄存器中内容为0时转移发生

    BEQZ R1,0

    BENZ

    条件转移指令,当寄存器中内容不为0时转移发生

    BNEZ R1,0

    BEQ

    条件转移指令,当两个寄存器内容相等时转移发生

    BEQ R1,R2

    BNE

    条件转移指令,当两个寄存器中内容不等时转移发生

    BNE R1,R2

    J

    直接跳转指令,跳转的地址在指令中

    J name

    JR

    使用寄存器的跳转指令,跳转地址在寄存器中

    JR R1

    JAL

    直接跳转指令,并带有链接功能,指令的跳转地址在指令中,跳转发生时要把返回地址存放到R31这个寄存器中

    JAL R1 name

    JALR

    使用寄存器的跳转指令,并且带有链接功能,指令的跳转地址在寄存器中,跳转发生时指令的放回地址放在R31这个寄存器中

    JALR R1

    MOV.S

    把一个单精度浮点数从一个浮点寄存器复制到另一个浮点寄存器

    MOV.S F0,F1

    MOV.D

    把一个双精度浮点数从一个浮点寄存器复制到另一个浮点寄存器

    MOV.D F0,F1

    MFC0

    把一个数据从通用寄存器复制到特殊寄存器

    MFC0 R1,R2

    MTC0

    把一个数据从特殊寄存器复制到通用寄存器

    MTC0 R1,R2

    MFC1

    把一个数据从定点寄存器复制到浮点寄存器

    MFC1 R1,F1

    MTC1

    把一个数据从浮点寄存器复制到定点寄存器

    MTC1 R1,F1

    LUI

    把一个16位的立即数填入到寄存器的高16位,低16位补零

    LUI R1,#42

    DSLL

    双字逻辑左移

    DSLL R1,R2,#2

    DSRL

    双字逻辑右移

    DSRL R1,R2,#2

    DSRA

    双字算术右移

    DSRA R1,R2,#2

    DSLLV

    可变的双字逻辑左移

    DSLLV R1,R2,#2

    DSRLV

    可变的双字罗伊右移

    DSRLV R1,R2,#2

    DSRAV

    可变的双字算术右移

    DSRAV R1,R2,#2

    SLT

    如果R2的值小于R3,那么设置R1的值为1,否则设置R1的值为0

    SLT R1,R2,R3

    SLTI

    如果寄存器R2的值小于立即数,那么设置R1的值为1,否则设置寄存器R1的值为0

    SLTI R1,R2,#23

    SLTU

    功能与SLT一致,但是带符号的

    SLTU R1,R2,R3

    SLTUI

    功能与SLT一致,但不带符号

    SLTUI R1,R2,R3

    MOVN

    如果第三个寄存器的内容为负,那么复制一个寄存器的内容到另外一个寄存器

    MOVN R1,R2,R3

    MOVZ

    如果第三个寄存器的内容为0,那么复制一个寄存器的内容到另外一个寄存器

    MOVZ R1,R2,R3

    TRAP

    根据地址向量转入管态

    ERET

    从异常中返回到用户态

    MADD.S

    一个双精度浮点数与单精度浮点数相乘加,结果为单精度

    MADD.D

    一个双精度浮点数与单精度浮点数相乘加,结果为双精度

    MADD.PS

    两个单精度浮点数相乘加,结果为单精度





    MIPS构架简介

        MIPS全称为icroprocessor without interlocked piped stages,意思是“无内部互锁流水级的微处理器”(M,其机制是尽量利用软件办法避免流水线中的数据相关问题。它最早是在80年代初期由斯坦福(Stanford)大学Hennessy教授领导的研究小组研制出来的。MIPS公司的R系列就是在此基础上开发的RISC工业产品的微处理器。这些系列产品为很多计算机公司采用构成各种工作站和计算机系统。 MIPS是出现最早的商业RISC架构芯片之一,新的架构集成了所有原来MIPS指令集,并增加了许多更强大的功能。

        MIPS是高效精简指令集计算机(RISC)体系结构中最优雅的一种;即使连MIPS的竞争对手也这样认为,这可以从MIPS对于后来研制的新型体系结构比如DEC的Alpha和HP的Precision产生的强烈影响看出来。虽然自身的优雅设计并不能保证在充满竞争的市场上长盛不衰,但是MIPS微处理器却经常能在处理器的每个技术发展阶段保持速度最快的同时保持设计的简洁。 

       MIPS的指令系统经过通用处理器指令体系MIPS I、MIPS II、MIPS III、MIPS IV到MIPS V,嵌入式指令体系MIPS16、MIPS32到MIPS64的发展已经十分成熟。在设计理念上MIPS强调软硬件协同提高性能,同时简化硬件设计。


    MIPS体系结构首先是一种RISC架构

    1 MIPS32架构中有32个通用寄存器,其中$0(无论你怎么设置,这个寄存器中保存的数据都是0)和$31(保存函数调用jal的返回地址)有着特殊的用途,其它的寄存器可作为通用寄存器用于任何一条指令中。

        虽然硬件没有强制性的指定寄存器使用规则,在实际使用中,这些寄存器的用法都遵循一系列约定。这些约定与硬件确实无关,但如果你想使用别人的代码,编译器和操作系统,你最好是遵循这些约定。

    [plain] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. ;REGISTER            NAME             USAGE  
    2. $0                   $zero            常量0(constantvalue 0)         永远返回值为0  
    3. $2-$3                $v0-$v1          子函数调用返回值(values for results and expressionevaluation)  
    4. $4-$7                $a0-$a3          子函数调用参数(arguments)  
    5. $8-$15               $t0-$t7          暂时的(或随便用的)  
    6. $16-$23              $s0-$s7          保存的(或如果用,需要SAVE/RESTORE的)(saved)  
    7.                                       子函数寄存器变量。子函数必须保存和恢复使用过的变量在函数 返回之前,从而调用函数知道这些寄存器的值没有变化。    
    8. $24-$25              $t8-$t9          暂时的(或随便用的)  
    9. $26-$27              $k0-$k1          通常被中断或异常处理程序使用作为保存一些系统参数  
    10. $28                  $gp              全局指针(GlobalPointer) 一些运行系统维护这个指针来更方便的存取“static“和”extern" 变量。  
    11. $29                  $sp              堆栈指针(StackPointer)  
    12. $30                  $fp              帧指针(FramePointer) 第9个寄存器变量。子函数可以用来做桢指针  
    13. $31                  $ra              子函数的返回地址(returnaddress)  


    2 MIPS32中如果有FPA
        将会有32个浮点寄存器,按汇编语言的约定为$f0~$f31,MIPS32中只能使用偶数号的浮点寄存器,奇数号的用途是:在做双精度的浮点运算时,存放该奇数号之前的偶数号浮点寄存器的剩余无法放下的32位。比如在做双精度的浮点运算时,$1存放$0的剩余的部分,所以在MIPS32中可以通过加载偶数号的浮点寄存器而把64位的双精度数据加载到两个浮点寄存器中,每个寄存器存放32位。

    比如:
    l.d $02, 24(t1)
    被扩充为两个连续的寄存器加载:
    lwc1 $f0, 24(t1)
    lwc1 $f1, 28(t1)



    3 MIPS架构中没有X86中的PC(程序计数)寄存器
       它的程序计数器不是一个寄存器。因为在MIPS这样具有流水线结构的CPU中,程序计数器在同一时刻可以有多个给定的值,如 jal 指令的返回地址跟随其后的第二条指令。
    ...
    jal printf
    move $4, $6
    xxx                          #return here after call
    MIPS32中也没有条件码,比如在X86中常见的状态寄存器中的Z、C标志位在MIPS32中是没有的,但是MIPS32中有状态寄存器


    4 MIPS32中不同于其它的RISC架构的地方是其有整数乘法部件
    这个部件使用两个特殊的寄存器HI、LO,并且提供相应的指令 mfhi/mthi,mthi/mtlo来实现整数乘法结果--hi/lo寄存器与通用寄存器之间的数据交换


    5 数据加载与存储.
      MIPS CPU可以在一个单一操作中存储1到8个字节。文档中和用来组成指令助记符的 命名约定如下:

    [plain] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. C名字            MIPS名字          大小(字节)                    汇编助记符  
    2. long long        dword                8                        "d"代表ld  
    3. int/long          word                4                        "w"代表lw  
    4. short            half word            2                        "h"代表lh  
    5. char              byte                1                         "b"代表lb  

    5.1数据加载.包括这样几条记载指令  LB/LBU、LH/LHU、LW
        byte和short的加载有两种方式。带符号扩展的lb和lh指令将数据值存放在32位寄存器的低位中,剩下的高位用符号位的值来扩充(位7如果是一个byte,位15如果是一个short)。这样就正确地将一个带符号整数放入一个32位的带符号的寄存器中。
       不带符号指令lbu和lhu用0来扩充数据,将数据存放在32位寄存器的低位中,并将高位用零来填充。例如,如果一个byte字节宽度的存储器地址为t1,其值为0xFE(-2或254如果是非符号数),那么将会在t2中放入0xFFFFFFFE(-2作为一个符号数)。t3的值会是0x000000FE(254作为一个非符号数)
    [plain] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. lb   t2, 0(t1)  
    2. lbu  t3, 0(t1)  

    5.2数据存储.包括这样几条指令SB、SH、SW
    由于加载就是把寄存器中的数据加载到内存中,所以不存在位扩展的问题。


    6 CP0 (协处理器0)--MIPS处理器控制.

    用于控制和设置MIPS CPU,里面包含了一些寄存器,通过对这些寄存器的不同的位的操作可以实现对处理器的设置
    CP0类似于X 86只能由内核 (高优先级权限)访问的一些处理器资源
    而前面提到的通用寄存器GPR和FPR则可以有由所有的优先级权限访问
    CP0提供了中断异常处理、内存管理(包括CACHE、TLB)、外设管理等途径(而这些只能由高优先级的内核才能访问到)。

    MIPS体系结构中集成了一个叫做 System Control Coprocessor (CP0)的部件。CP0就是我们常说的MMU控制器。在CP0中,除了TLB entry(例如,对RM5200,有48pair,96个TLB entry),一些控制寄存器提供给OSKERNEL来控制MMU的行为。每个CP0控制寄存器都对应一个唯一的寄存器号。MIPS提供特殊的指令来对CP0进行操作。

    [plain] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. mfc0 reg. CP0_REG                把一个数据从特殊寄存器复制到通用寄存器                
    2. mtc0 reg. CP0_REG                把一个数据从通用寄存器复制到特殊寄存器      

    我们通过上述的两条指令来把一个GPR寄存器的值assign给一个CP0寄存器,从而达到控制MMU的目的。

    面简单介绍几个与TLB相关的CP0控制寄存器。
    Index Register
    这个寄存器是用来指定TLB entry的,当你进行TLB读写的时候。我们已经知道,例如,MIPS R5提供48个TLBpair,所以index寄存器的值是从0到47。换句话说,每次TLB写的行为是对一个pair发生的。这一点是与其他的CPU MMUTLB 读写不同的。 EntryLo0, EntryLo1 这两个寄存器是用来specify 一个TLBpair的偶(even)和奇(odd)物理(Physical)页面地址。


    6.1常见的MIPS CPU控制寄存器包括:

    SR( 状态寄存器) 12
    Config (CPU参数设置寄存器)-16
    EPC (例外程序寄存器)13、 

    CAUSE(导致中断和异常的原因寄存器) 14、

    BadVaddr(地址错误时存放地址的寄存器)8
    Index-0、Random-1、EntryLo0-2、EntryLo1-3、EntryHi-10、PageMask
    Count-9、Compare-11共同组成了高精度的时钟


    6.2CP0寄存器的访问指令

    mtc0 ts,                 #把通用寄存器 ts中的数据送到协处理器0中的寄存器nn
    mfc0 ts,                 #把送到协处理器0中寄存器 nn 的值送到通用寄存器ts
    dmtc0 ts,              #把通用寄存器 ts中的数据送到协处理器0中的寄存器nn
    dmfc0 ts,              #把送到协处理器0中寄存器 nn 的值送到通用寄存器ts



    6.3起作用的寄存器及其作用时机
    加电后:你需要设置SR和Config寄存器,以确保CPU进入正确的引导状态,并且SR寄存器还设置了中断码。以决定系统响应哪些中断。
    进入任何异常:处理任何例外都会调用一个“通用异常处理程序”。MIPS体系并没有为进入异常作任何的寄存器保存,也没有关于堆栈方面的任何支持,进入异常时唯一保存的就是                              异 常返回地址保存在EPC中。所以这些都需要操作系统的软件实现。操作系统可以使用K0或者K1寄存器作为堆栈指针,指向某个位置,并且在需要保存的寄存器

                             保存到这个栈上。然后通过Cause寄存器找到发生异常的原因,这样才能跳转到对应的中断处理程序中。
    从异常返回:  从异常返回到EPC制定的地址之前要把CPU的状态回复到异常之前,好象什么事情都没有发生一样。在R3000中使用rfe指令作这样的事情,但是着条指令仅仅恢复了                         一些寄存器中的内容,但是并没有转移控制指令,你需要把EPC内容保存到一个通用寄存器中,然后调用jr指令返回到EPC指向的地址处,


    7 MIPS的存储管理模型.MIPS32中的存储器模型被划分为四个大块,其中:
    0x0000,0000~0x7fff,ffff(0~2G-1) USEG
    must be mapped (set page table and TLB)and set cache before use
    0x8000,0000~0x9fff,ffff(2G~2.5G-1) KSEG0
    directly mapped(no need to set page table and TLB) but need to set cache before use
    0xa000,0000~0xbfff,ffff(2.5G~3G-1) KSEG1
    directly mapped(no need to set page table and TLB) and never use cache
    0xc000,0000~0xffff,ffff(3G~4G-1) KSEG2
    muse be mapped(set page table and TLB) and set cache before use


    这样的存储器管理模型和X86差距比较大,X86有一个实模式,内核在启动保护模式之前,运行在实模式之下,直到设定了保护模式之后才能运行在保护模式下。在MIPS32中没有保护模式那么系统是如何启动的呢?

    可以直观的看到只有kseg1是不需要映射(物理虚拟转换),没有被缓存的,也就是说只有kseg1的内存区域可以做引导的存储区(在这里放置引导用flash 存储器).被cached区域必须等到MMU 的TLB被初始化后才可以使用的。

    MIPS32中的系统启动向量位于KSEG1中0xbf10,0000,由于KSEG1是directly mapped的,所以直接对应了物理地址0x1fc0,0000,你可以在内核中一直使用0xa000,0000~0xbfff,ffff之间的虚拟地址来访问物理地址0~512M-1,在设置了KSEG0的cache之后,也可一使用0x8000,0000~0x9fff,ffff之间的虚拟地址来访问0~512M-1之间的物理地址。对于512M以上的物理地址只能由KSEG2和USEG通过页表访问。


    8 MIPS32中的状态寄存器SR.状态寄存器来设置处理器的一些功能集合,包括设置

    设置协处理器0~3的可用性的位 CU0~CU3(28~31)
    复位向量  BEV
    中断屏蔽位8~15
    KUc、IEc0~1,基本的CPU保护单位
    KUc为1时表示运行在内核态,为0时运行在用户模式。在内核态下,可以访问所有的地址空间和协处理器0,运行在用户态下值只能访问0x0000,0000~0x7fff,ffff之间的地址空间。
    KUp、IEp2~3
    当异常发生时,硬件把KUc、IEc的值保存到KUp、IEp中,并且将KUc、IEc设置为[1,0]--内核态、关中断。异常返回时rfe指令可以把KUp、IEp的内容复制到KUc、IEc中
    KUo、IEo
    当异常发生时,硬件把KUp、IEp的值保存到KUo、IEo中;返回时把KUo、IEo的内容复制到KUp、IEp中。
    上面三对KU/IE位构成了深度2的栈,异常发生时,硬件自动压栈,rfe指令从异常返回时,从栈中恢复数值
    还有一些其它的功能和状态位,可以参考相应的文档


    9 MIPS32中的Cause寄存器 

    BD位:EPC中正常情况下存放了发生异常的指令,但是当着条指令存放在调转指令的延迟槽中时,那么EPC中存放的是这个跳转指令,否则这条跳转指令将得不到执行。
    IP位:告诉用户来临的中断
    ExcCode:这是一个5位的代码,告诉你哪一条异常发生了,可以根据这个从通用异常处理程序跳装到特定异常处理程序中。

    10 MIPS32的C语言中参数传递和返回值的约定 

    caller至少使用16bytes 堆栈空间存放参数,然后把这16 bytes存放到通用寄存器a0~a3中, called subroutine 直接使用寄存器中的参数,同时caller 堆栈中的16bytes的数据可以不去理会了。
    需要理解的是带有浮点参数和结构体的参数传递,对于带有浮点参数的传递需要看第一个参数是否是浮点,如果是浮点则将参数放到 $f12和$f14这两个浮点寄存器中,如果第一个参数不是浮点数,则不用浮点寄存器存放参数。对于结构体的参数传递和x86类似
    对于整数和指针类型的参数返回值一般通过通用寄存器v0($2)返回,对于浮点返回类型,一般存放在$f0中返回。



    参考文章:

    http://mips.eefocus.com/article/10-04/261271061334.html

    http://www.52solution.com/basic/1678?page=1



    指令

    功能

    应用实例

    LB

    从存储器中读取一个字节的数据到寄存器中

    LB R1, 0(R2)

    LH

    从存储器中读取半个字的数据到寄存器中

    LH R1, 0(R2)

    LW

    从存储器中读取一个字的数据到寄存器中

    LW R1, 0(R2)

    LD

    从存储器中读取双字的数据到寄存器中

    LD R1, 0(R2)

    L.S

    从存储器中读取单精度浮点数到寄存器中

    L.S R1, 0(R2)

    L.D

    从存储器中读取双精度浮点数到寄存器中

    L.D R1, 0(R2)

    LBU

    功能与LB指令相同,但读出的是不带符号的数据

    LBU R1, 0(R2)

    LHU

    功能与LH指令相同,但读出的是不带符号的数据

    LHU R1, 0(R2)

    LWU

    功能与LW指令相同,但读出的是不带符号的数据

    LWU R1, 0(R2)

    SB

    把一个字节的数据从寄存器存储到存储器中

    SB R1, 0(R2)

    SH

    把半个字节的数据从寄存器存储到存储器中

    SH R1,0(R2)

    SW

    把一个字的数据从寄存器存储到存储器中

    SW R1, 0(R2)

    SD

    把两个字节的数据从寄存器存储到存储器中

    SD R1, 0(R2)

    S.S

    把单精度浮点数从寄存器存储到存储器中

    S.S R1, 0(R2)

    S.D

    把双精度数据从存储器存储到存储器中

    S.D R1, 0(R2)

    DADD

    把两个定点寄存器的内容相加,也就是定点加

    DADD R1,R2,R3

    DADDI

    把一个寄存器的内容加上一个立即数

    DADDI R1,R2,#3

    DADDU

    不带符号的加

    DADDU R1,R2,R3

    DADDIU

    把一个寄存器的内容加上一个无符号的立即数

    DADDIU R1,R2,#3

    ADD.S

    把一个单精度浮点数加上一个双精度浮点数,结果是单精度浮点数

    ADD.S F0,F1,F2

    ADD.D

    把一个双精度浮点数加上一个单精度浮点数,结果是双精度浮点数

    ADD.D F0,F1,F2

    ADD.PS

    两个单精度浮点数相加,结果是单精度浮点数

    ADD.PS F0,F1,F2

    DSUB

    两个寄存器的内容相减,也就是定点数的减

    DSUB R1,R2,R3

    DSUBU

    不带符号的减

    DSUBU R1,R2,R3

    SUB.S

    一个双精度浮点数减去一个单精度浮点数,结果为单精度

    SUB.S F1,F2,F3

    SUB.D

    一个双精度浮点数减去一个单精度浮点数,结果为双精度浮点数

    SUB.D F1,F2,F3

    SUB.PS

    两个单精度浮点数相减

    SUB.SP F1,F2,F3

    DDIV

    两个定点寄存器的内容相除,也就是定点除

    DDIV R1,R2,R3

    DDIVU

    不带符号的除法运算

    DDIVU R1,R2,R3

    DIV.S

    一个双精度浮点数除以一个单精度浮点数,结果为单精度浮点数

    DIV.S F1,F2,F3

    DIV.D

    一个双精度浮点数除以一个单精度浮点数,结果为双精度浮点数

    DIV.D F1,F2,F3

    DIV.PS

    两个单精度浮点数相除,结果为单精度

    DIV.PS F1,F2,F3

    DMUL

    两个定点寄存器的内容相乘,也就是定点乘

    DMUL R1,R2,R3

    DMULU

    不带符号的乘法运算

    DMULU R1,R2,R3

    MUL.S

    一个双精度浮点数乘以一个单精度浮点数,结果为单精度浮点数

    DMUL.S F1,F2,F3

    MUL.D

    一个双精度浮点数乘以一个单精度浮点数,结果为双精度浮点数

    DMUL.D F1,F2,F3

    MUL.PS

    两个单精度浮点数相乘,结果为单精度浮点数

    DMUL.PS F1,F2,F3

    AND

    与运算,两个寄存器中的内容相与

    ANDR1,R2,R3

    ANDI

    一个寄存器中的内容与一个立即数相与

    ANDIR1,R2,#3

    OR

    或运算,两个寄存器中的内容相或

    ORR1,R2,R3

    ORI

    一个寄存器中的内容与一个立即数相或

    ORIR1,R2,#3

    XOR

    异或运算,两个寄存器中的内容相异或

    XORR1,R2,R3

    XORI

    一个寄存器中的内容与一个立即数异或

    XORIR1,R2,#3

    BEQZ

    条件转移指令,当寄存器中内容为0时转移发生

    BEQZ R1,0

    BENZ

    条件转移指令,当寄存器中内容不为0时转移发生

    BNEZ R1,0

    BEQ

    条件转移指令,当两个寄存器内容相等时转移发生

    BEQ R1,R2

    BNE

    条件转移指令,当两个寄存器中内容不等时转移发生

    BNE R1,R2

    J

    直接跳转指令,跳转的地址在指令中

    J name

    JR

    使用寄存器的跳转指令,跳转地址在寄存器中

    JR R1

    JAL

    直接跳转指令,并带有链接功能,指令的跳转地址在指令中,跳转发生时要把返回地址存放到R31这个寄存器中

    JAL R1 name

    JALR

    使用寄存器的跳转指令,并且带有链接功能,指令的跳转地址在寄存器中,跳转发生时指令的放回地址放在R31这个寄存器中

    JALR R1

    MOV.S

    把一个单精度浮点数从一个浮点寄存器复制到另一个浮点寄存器

    MOV.S F0,F1

    MOV.D

    把一个双精度浮点数从一个浮点寄存器复制到另一个浮点寄存器

    MOV.D F0,F1

    MFC0

    把一个数据从通用寄存器复制到特殊寄存器

    MFC0 R1,R2

    MTC0

    把一个数据从特殊寄存器复制到通用寄存器

    MTC0 R1,R2

    MFC1

    把一个数据从定点寄存器复制到浮点寄存器

    MFC1 R1,F1

    MTC1

    把一个数据从浮点寄存器复制到定点寄存器

    MTC1 R1,F1

    LUI

    把一个16位的立即数填入到寄存器的高16位,低16位补零

    LUI R1,#42

    DSLL

    双字逻辑左移

    DSLL R1,R2,#2

    DSRL

    双字逻辑右移

    DSRL R1,R2,#2

    DSRA

    双字算术右移

    DSRA R1,R2,#2

    DSLLV

    可变的双字逻辑左移

    DSLLV R1,R2,#2

    DSRLV

    可变的双字罗伊右移

    DSRLV R1,R2,#2

    DSRAV

    可变的双字算术右移

    DSRAV R1,R2,#2

    SLT

    如果R2的值小于R3,那么设置R1的值为1,否则设置R1的值为0

    SLT R1,R2,R3

    SLTI

    如果寄存器R2的值小于立即数,那么设置R1的值为1,否则设置寄存器R1的值为0

    SLTI R1,R2,#23

    SLTU

    功能与SLT一致,但是带符号的

    SLTU R1,R2,R3

    SLTUI

    功能与SLT一致,但不带符号

    SLTUI R1,R2,R3

    MOVN

    如果第三个寄存器的内容为负,那么复制一个寄存器的内容到另外一个寄存器

    MOVN R1,R2,R3

    MOVZ

    如果第三个寄存器的内容为0,那么复制一个寄存器的内容到另外一个寄存器

    MOVZ R1,R2,R3

    TRAP

    根据地址向量转入管态

    ERET

    从异常中返回到用户态

    MADD.S

    一个双精度浮点数与单精度浮点数相乘加,结果为单精度

    MADD.D

    一个双精度浮点数与单精度浮点数相乘加,结果为双精度

    MADD.PS

    两个单精度浮点数相乘加,结果为单精度





    展开全文
  • 3. 实现MIPS的部分I型和 R型指令的功能 解决方法 1. 分析MIPS I型指令的特点,与R型指令有明显的不同:没有rd寄存器,使用rt作为目的寄存器;源操作数中有一个为立即数,位于指令的低16位 2. 在寄存器堆模块的写地址...

    实验内容

    1. 掌握MIPS R型和I型指令的综合数据通路设计,掌握数据流的多路选通控制方法
    2. 掌握取数指令lw和存数指令sw的寻址方式及其有效地址产生的方法
    3. 实现MIPS的部分I型和 R型指令的功能

    解决方法

    1. 分析MIPS I型指令的特点,与R型指令有明显的不同:没有rd寄存器,使用rt作为目的寄存器;源操作数中有一个为立即数,位于指令的低16位
    2. 在寄存器堆模块的写地址输入端口设置二选一选择器,由于R型和I型的目的寄存器不同,由rd_rt_s控制
    3. 16位的立即数imm需要经过扩展才能与rs执行运算操作,对于有符号数的操作,执行的是符号扩展,对于无符号数的操作,执行的是0扩展
    4. R型指令执行rs和rt运算,结果送rd;而I型立即数即数寻址指令则执行rs和扩展后的立即数imm运算,结果送rt。因此ALU的输入数据B端有两个选择:rt或者imm,仍可以通过二选一数据选择器,用rt_imm_s控制信号
    5. 需要添加一个数据存储器RAM存放指令访问的数据,读出的数据,意味着要在寄存器堆的写端口加个选择器,用alu_mem_s控制信号,其中要注意一点就是数据存储器的clk至少是CPU频率的2倍以上,我使用了两个clk输入解决这个问题
    6. 在实际写代码时,要注意顶层模块中,实例下层模块的顺序,由于译码模块变量多,我将其抽离出来,为了使顶层模块看起来简洁
    7. 涉及实验: 具体用到的实验是多功能ALU设计实验寄存器堆设计实验取指令与指令译码实验
    8. 代码展示

    顶层模块

    module CPU(clk,rst,OF,ZF,F,ALU_OP,M_R_Data,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s,Write_Reg,clk_M,R_Data_B,Inst_code);
    input clk,rst,clk_M;
    wire [31:0]Inst_code;
    wire [5:0]op_code,funct;
    wire [4:0]rs_addr,rt_addr,rd_addr,shamt;
    output [31:0]F;
    output OF,ZF;
    output [31:0]M_R_Data;
    output [2:0]ALU_OP;
    wire [31:0]Mem_Addr;
    wire [4:0]W_Addr;
    output rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s,Write_Reg;
    output [31:0]Inst_code;
    wire [31:0]imm_data;
    wire [31:0]R_Data_A;
    output [31:0] R_Data_B;
    wire [15:0]imm;
    wire [31:0]ALU_B;
    wire [31:0]W_Data;
    PC pc1(clk,rst,Inst_code);
    assign op_code = Inst_code[31:26];
    assign rs_addr = Inst_code[25:21];
    assign rt_addr = Inst_code[20:16];
    assign rd_addr = Inst_code[15:11];
    assign shamt = Inst_code[10:6];
    assign funct = Inst_code[5:0];
    assign imm = Inst_code[15:0];
    OP_Func op(op_code,funct,Write_Reg,ALU_OP,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s);
    assign W_Addr = (rd_rt_s)?rt_addr:rd_addr;
    assign imm_data = (imm_s)?{{16{imm[15]}},imm}:{{16{1'b0}},imm};
    assign W_Data = alu_mem_s?M_R_Data:F;
    Fourth_experiment_first 	F1(rs_addr,rt_addr,Write_Reg,R_Data_A,R_Data_B,rst,clk,W_Addr,W_Data);
    assign ALU_B = (rt_imm_s)?imm_data:R_Data_B;	
    Third_experiment_first T1(OF,ZF,ALU_OP,R_Data_A,ALU_B,F); 
    RAM RAM_B (
      .clka(clk_M), // input clka
      .wea(Mem_Write), // input [0 : 0] wea
      .addra(F[5:0]), // input [5 : 0] addra
      .dina(R_Data_B), // input [31 : 0] dina
      .douta(M_R_Data) // output [31 : 0] douta
    );
    endmodule
    
    

    PC(取指令模块)

    module PC(clk,rst,Inst_code);
    input clk,rst;
    wire [31:0]PC_new;
    reg[31:0]PC;
    initial
    	PC = 32'h0000_0000;
    output [31:0]Inst_code;
    assign PC_new = PC +4;
    Inst_Rom rom(
      .clka(clk), // input clka
      .addra(PC[7:2]), // input [5 : 0] addra
      .douta(Inst_code) // output [31 : 0] douta
    );
    always@(negedge clk or posedge rst)
    	begin
    		if(rst)
    			begin PC <= 32'h0000_0000; end
    		else
    			begin PC <= PC_new; end
    	end
    endmodule
    

    OP_Func(译码模块)

    module OP_Func(op_code,funct,Write_Reg,ALU_OP,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s);
    input [5:0]op_code;
    input [5:0]funct;
    output reg[2:0]ALU_OP;
    output reg Write_Reg;
    output reg rd_rt_s;
    output reg imm_s;
    output reg rt_imm_s;
    output reg Mem_Write;
    output reg alu_mem_s;
    always@(*)
    	begin	
    			Write_Reg=1;
    			ALU_OP=0;
    			rd_rt_s=0;
    			imm_s=0;
    			rt_imm_s=0;
    			Mem_Write=0;
    			alu_mem_s=0;
    				if(op_code==0)
    					begin 
    						case(funct)
    						6'b100000:begin ALU_OP=3'b100; end
    						6'b100010:begin ALU_OP=3'b101; end
    						6'b100100:begin ALU_OP=3'b000;end
    						6'b100101:begin ALU_OP=3'b001;end
    						6'b100110:begin ALU_OP=3'b010;end
    						6'b100111:begin ALU_OP=3'b011;end
    						6'b101011:begin ALU_OP=3'b110;end
    						6'b000100:begin ALU_OP=3'b111;end
    						endcase 
    					end
    				else
    					begin
    						case(op_code)
    							6'b001000:begin rd_rt_s=1;imm_s=1;rt_imm_s=1;ALU_OP=100;end  
    							6'b001100:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=000; end  
    							6'b001110:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=010;end  
    							6'b001011:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=110; end  
    							6'b100011:begin rd_rt_s=1;imm_s=1;rt_imm_s=1;alu_mem_s=1;ALU_OP=100; end  
    							6'b101011:begin imm_s=1;rt_imm_s=1;ALU_OP=100;Write_Reg=0;Mem_Write=1; end  
    					endcase
    				end
    			end
    endmodule
    

    Fourth_experiment_first(寄存器堆模块)

    module Fourth_experiment_first(R_Addr_A,R_Addr_B,Write_Reg,R_Data_A,R_Data_B,Reset,Clk,W_Addr,W_Data);
    input [4:0]R_Addr_A,R_Addr_B,W_Addr;
    input Write_Reg,Reset,Clk;
    input[31:0] W_Data;
    output [31:0] R_Data_A,R_Data_B;
    reg [31:0] REG_Files[0:31];
    integer i=0;
    initial
            for(i=0;i<32;i=i+1) REG_Files[i]<=0;
    always @ (posedge Clk or posedge Reset)
    	begin
    		if(Reset)
    			begin
    				for(i=0;i<=31;i=i+1)
    					REG_Files[i]<=0;
    			end
    		else
    			begin
    				if(Write_Reg)
    					REG_Files[W_Addr]<=W_Data;
    			end
    	end
    	assign R_Data_A = REG_Files[R_Addr_A];
    	assign R_Data_B = REG_Files[R_Addr_B];
    endmodule
    
    

    Third_experiment_first(ALU模块)

    module Third_experiment_first(OF,ZF,ALU_OP,A,B,F);
    input [2:0]ALU_OP;
    input [31:0]A,B;
    output reg[31:0]F;
    reg C32;
    output reg OF;
    output reg ZF;
    always @(ALU_OP or A or B)
     begin
    	OF = 0;
    	C32 = 0;
    	case(ALU_OP)
    			 3'b000:F<=A&B;
    			 3'b001:F<=A|B;
    			 3'b010:F<=A^B;
    			 3'b011:F<=A~^B;
    			 3'b100:{C32,F}<=A+B;
    			 3'b101:{C32,F}<=A-B;
    			 3'b110:begin if(A<B)  F<=32'h0000_0001;else F<=32'h0000_0000;end
    			 3'b111:begin F<=B<<A;end
    	endcase
    	if(F==32'h0000_0000)	
    			ZF<=1;
    	else
    			ZF<=0;
    	if(ALU_OP == 3'b100 || ALU_OP == 3'b101)
    		OF<=C32^F[31]^A[31]^B[31];	
    	else
    		OF <=0; 
    	end
    endmodule
    

    MIPS32.coe

    memory_initialization_radix=16;
    memory_initialization_vector=38011234,20026789,20039000,38040010,00822804,00253025,00833804,00464020,00414822,00225022,206b7fff,206c8000,314dffff,2c4e6788,2c4f678a,ac8b0000,ac0c0014,ac8d0010,ac8e0014,8c100010,8c910004,02119025,8c930010,8c940014,0274a827,8c96fff0,8c97fff4,02d7c02b;
    

    数据coe

    memory_initialization_radix=16;
    memory_initialization_vector=88888888,99999999,00010fff,20006789,FFFF0000,0000FFFF,88888888,99999999,
    aaaaaaaa,bbbbbbbb,00000820,00632020,00010fff,20006789,FFFF0000,0000FFFF,88888888,99999999,aaaaaaaa,bbbbbbbb,00000820,00632020,00010fff,
    20006789,FFFF0000,0000FFFF,88888888,99999999,aaaaaaaa,bbbbbbbb,00000820,00632020,00010fff,20006789,FFFF0000,0000FFFF,88888888,99999999,aaaaaaaa,bbbbbbbb,
    00000820,00632020,00010fff,20006789,FFFF0000,0000FFFF,88888888,99999999,aaaaaaaa,bbbbbbbb,12345678,23456789,3456789a,6789abcd;
    

    测试模块

    module test;
    	reg clk;
    	reg rst;
    	reg clk_M;
    	wire OF;
    	wire ZF;
    	wire [31:0] F;
    	wire [2:0] ALU_OP;
    	wire [31:0] M_R_Data;
    	wire rd_rt_s;
    	wire imm_s;
    	wire rt_imm_s;
    	wire Mem_Write;
    	wire alu_mem_s;
    	wire Write_Reg;
    	wire [31:0] R_Data_B;
    	wire [31:0] Inst_code;
    	CPU uut (
    		.clk(clk), 
    		.rst(rst), 
    		.OF(OF), 
    		.ZF(ZF), 
    		.F(F), 
    		.ALU_OP(ALU_OP), 
    		.M_R_Data(M_R_Data), 
    		.rd_rt_s(rd_rt_s), 
    		.imm_s(imm_s), 
    		.rt_imm_s(rt_imm_s), 
    		.Mem_Write(Mem_Write), 
    		.alu_mem_s(alu_mem_s), 
    		.Write_Reg(Write_Reg), 
    		.clk_M(clk_M), 
    		.R_Data_B(R_Data_B), 
    		.Inst_code(Inst_code)
    	);
    	always #9  clk_M = ~clk_M;
    	always #20 clk =~clk;
    	initial begin
    		clk = 0;
    		rst = 1;
    		clk_M = 0;
    		#2;
          rst = 0;
    	end     
    endmodule
    

    友情提示

    1.有的同学会把在顶层模块存数据存储器的地址和PC的地址弄混,大家会问为什么PC的存储器是取[7:2],而顶层模块存数据存储器的地址[5:0],主要原因就在PC=PC+4这个语句上,我们的存储器还是按照字节去寻址的,如果我们不取[7:2]的地址就会导致中间几条指令跳过,而顶层数据模块就是逐一增加的
    2.数据存储器的clk至少是CPU频率的2倍以上
    3.开始的时候,rst一定要拉高哦

    展开全文
  • mips指令

    2013-01-22 16:45:14
    功能 应用实例 LB 从存储器中读取一个字节数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字数据到寄存器中 LH R1, 0(R2) LW ...
  • MIPS 指令 系统中常用指令

    千次阅读 2011-11-14 20:07:21
    指令 功能 应用实例 LB 从存储器中读取一个字节数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字数据到寄存器中 LH R1, 0(R2) LW 从存储器...
  • MIPS64指令系统

    千次阅读 2013-03-10 20:07:13
    指令 功能 应用实例 LB 从存储器中读取一个字节数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字数据到寄存器中 LH R1, 0(R2) LW 从存储器中读取一个字数据到寄存器中 LW R1, 0(R2) LD 从...
  • 指令 功能 应用实例 LB 从存储器中读取一个字节数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字数据到寄存器中 LH R1, 0(R2) LW 从存储器中读取一个字数据到寄存器中 LW R1...
  • 表1字节交换指令使用格式及功能LADSTL功能及说明SWAP IN 功能:使能输入EN有效时,将输入字IN高字节与低字节交换,结果仍放在IN中IN:VW, IW, QW, MW, SW, SMW, T, C, LW, AC。数据类型:字ENO = 0错误条件:0006...
  • 指令  功能  应用实例   LB  从存储器中读取一个字节数据到寄存器中  LB R1, 0(R2)   LH  从存储器中读取半个字数据到寄存器中  LH R1, 0(R2)   LW  从存储器中读取一个字数据到寄存器...
  • 2、上述指令的指令编码、代码、功能以及在单周期中的数据通路,条件分支指令的地址计算、单周期各功能部件的控制信号值判断 3、中断和异常的处理时机 一、MIPS指令 注:时钟部件 二、数据通路 合并 (1)R型...
  • 预计最低会做到支持{add,sub,ori,lw,sw,beq,j }指令的五级流水线 版本1.0 实现了一个原始的支持ori指令的五级流水线 例如如下指令: ori $1 $s0 0x0013 #将0号寄存器的值与0x0013进行或操作,结果储存...
  • 每条指令的编码长度均为 32 位。 2.采用 5 级流水线技术,具有数据前推机制。 3.具有解决控制冒险,数据冒险等问题的能力,能够插入气泡暂停等。 4.具有缩短分支的延迟等方案。 详细分析过程及代码分析参见:...
  • 基本指令:Add, Sub, And, Or, Addi, Ori, Sll, Srl, Lw, Sw, Lui, Slt, Slti, Beq, Bne, J, Jal, Jr 扩展指令:Lb, Lbu, Lh, Lhu, Sb, Sh, Addu, Subu, Sltu, Xor, Nor, Sra, Mult, Multu, Div, Divu, Addi, Addiu,...
  • 单周期CPU设计(一)

    2020-05-23 19:39:57
    设计过程分两步,首先,根据所设计的所有汇编指令的功能及指令格式,完成CPU的数据通路设计;其次,根据指令功能和数据通路设计控制部件。 数据通路的一般设计方法: 1.根据指令的功能,确定每条指令在执行过程中所...
  • C程序编译过程

    2010-03-28 11:13:00
     编译,编译程序读取源程序(字符流),对之进行词法和语法分析,将高级语言指令转换为功能等效汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式要求链接生成可执行程序。...
  • logisim计组实验十 单周期MIPS CPU

    千次阅读 多人点赞 2020-06-23 09:46:42
    文章目录mips指令格式指令指令译码逻辑ALU控制逻辑控制信号 ...OP不为0,能够唯一确定不同的功能 I型指令有两个操作数Rs和Rt 指令 lw: addi: sw: beq: bne: add: syscall: slt: 辅助指令R_TYPE: 用
  • MIPSter-crx插件

    2021-04-01 22:15:05
    语言:English 将mips指令转换为机器代码...当前受支持的指令为:add,addi和beq,lw或slt,sub *注意:每个指令和逗号后面必须有一个尾随空格。 输入示例->加$ s0,$ s1,$ s2 sub $ s3,$ s4,$ s5 lw $ t2、32($ 0)
  • 计算机组成原理慕课测试-期末考试

    千次阅读 2020-01-12 10:59:27
    假设一个门电路时间延迟...多周期CPU设计实验中LW指令一共需要多少个时钟周期 5 在小数定点机中,下列关于原码、反码、补码描述中正确是 B A.三种机器数都能表示-1 B.只有补码能表示-1 C.只有原码能表示-...

空空如也

空空如也

1 2
收藏数 40
精华内容 16
热门标签
关键字:

lw指令的功能