精华内容
下载资源
问答
  • 我们都知道,在MIPS指令级架构中,采用的都是定长指令,即就是每一个指令都是32位,分为R型(6, 5, 5, 5, 5, 6),I型(6, 5, 5,16),J型(6, 26), 在这所有指令中,是lw(存指令)运行时间最长,对于这个原因...

    我们都知道,在MIPS指令级架构中,采用的都是定长指令,即就是每一个指令都是32位,分为R型(6, 5, 5, 5, 5, 6),I型(6, 5, 5,16),J型(6, 26), 在这所有指令中,是lw(存指令)运行时间最长,对于这个原因,从宏观上来理解,就是我们在内存中采用32个32位的通用寄存器来存和指令有关的东西,比如说是一个数组的话,我们只会在这个通用寄存器中将此数组的首地址存下来,要访问这个数组的其他部分的时候,利用sw指令,将首地址加上一个偏移量(offset)的方法得到一个地址(应该在外存储器),然后将此地址中的值暂时拿回到内存中的某个寄存器中,(这就是sw指令所完成的功能),也正是因为这样,造成sw指令是所有指令中运行时间最长的,因为从外存储器向内存储器读入数据到寄存器中相对于从寄存器读入是很慢的。下面贴一张时间做个参考

    这里多说一下sw指令是不需要在指令运行期间访问外存的,我个人的理解就是sw指令是需要访问外存的,因为他要把数组中的数据存到外存中,但这对于我们指令的运行来说是不耽误整个指令的运行时间的。

    展开全文
  • MIPS架构下LW指令的重定位过程

    千次阅读 2019-09-27 12:39:21
    之前的文章介绍了MIPS架构下函数跳转指令bal和jal和重定位过程,感兴趣的同学可以跳转到××查看,本章通过分析lw 指令来分析从内存加载数据到寄存器的重定位的过程。 本文有点烧脑,看完注意休息 “_” 首先看...

    通常我们不会去关心指令重定位(relocation)的细节,编译器的ld过程已经帮助我们做好了。由于最近在移植CRIU,涉及到指令的重定位计算,不得不细细研究代码重定位的细节知识。之前的文章介绍了MIPS架构下函数跳转指令bal和jal和重定位过程,感兴趣的同学可以跳转到https://blog.csdn.net/weixin_38669561/article/details/100536803查看,本章通过分析lw 指令来分析从内存加载数据到寄存器的重定位的过程。

    本文有点烧脑,看完注意休息 “_

    一、准备工作和基础知识

    可以跳过
    首先看下面的示例汇编语句:

    //test.S
    ENTRY(__export_parasite_head_start)
    	.set noreorder
    	lw	a0, __value
    	jr ra
    
    __value:
    	.long 0
    END(__export_parasite_head_start)
    

    这里lw a0,__value 就是我们要分析的汇编指令。我们用gcc编译

    $ gcc -save-temps -g -c -fno-builtin -mno-abicalls test.S 
    

    其中 -save-temps 参数意味着保留中间临时文件,所以这条命令执行完成会发现当前目录多了两个文件,test.s和test.o。其中test.s就是GCC编译生成的中间编译文件,而test.o是汇编文件。编译文件和汇编文件有什么区别呢?首先要了解GCC编译是有4个过程,预编译(生成.i文件)-> 编译(生成.s文件)->汇编(生成.o文件)->链接(生成可执行文件,默认为a.out)。这里的test.s就是编译阶段产生的文件,test.o就是汇编阶段产生的文件,编译和汇编的区别可以通过查看文件内容得知:

    //test.s
     .section .head.text, "ax"
    .globl __export_parasite_head_start; .align 4; .type __export_parasite_head_start, @function; __export_parasite_head_start:
     .set noreorder
     lw $4, __export_parasite_cmd
     jr $31
    __export_parasite_cmd:
     .long 2
    .size __export_parasite_head_start, . - __export_parasite_head_start
    

    可以看出test.s和test.S几乎没有差别,都是汇编指令。
    test.o已经是ELF格式的文件了,所以不能直接打开,需要使用objdump命令

    $ objdump -D test.o > test.o.dump
    

    然后打开文件test.o.dump

    test.o:     文件格式 elf64-tradlittlemips
    	...
    Disassembly of section .head.text:
    0000000000000000 <__export_parasite_head_start>:
       0:	3c040000 	lui	a0,0x0
       4:	3c010000 	lui	at,0x0
       8:	64840000 	daddiu	a0,a0,0
       c:	0004203c 	dsll32	a0,a0,0x0
      10:	0081202d 	daddu	a0,a0,at
      14:	8c840000 	lw	a0,0(a0)
      18:	03e00008 	jr	ra
    
    000000000000001c <__export_parasite_cmd>:
      1c:	00000002 	srl	zero,zero,0x0
          ...
    
    

    汇编过程就是将汇编代码(test.s)转变成机器可以执行的指令(test.o),有些汇编语句和机器指令一一对应,不需要扩展,比如上面的 "jr ra" 指令。有些汇编指令可能扩展成多条机器指令,比如test.S里里面的 "lw a0, __value" 扩展成了6条指令

       0:	3c040000 	lui	a0,0x0
       4:	3c010000 	lui	at,0x0
       8:	64840000 	daddiu	a0,a0,0
       c:	0004203c 	dsll32	a0,a0,0x0
      10:	0081202d 	daddu	a0,a0,at
      14:	8c840000 	lw	a0,0(a0)
    

    同时我们有知道,此时的test.o还是没有做重定位的指令集,从起始地址"0000000000000000"就可以看出,或者使用file命令

    $ file test.o
    test.o: ELF 64-bit LSB relocatable, MIPS, MIPS64 rel2 version 1 (SYSV), not stripped
    

    这里 "relocatable"就意味着这是需要重定位的文件,或者说需要做指令修正的文件。
    那么重定位什么时候做呢?链接阶段。上面我在使用gcc工具时有一个参数 "-c" 。这个值意思是制作编译、汇编,不进行链接。链接过程主要包括了地址和空间分配、符号决议和重定位。

    下面我们使用ld工具来进行test.o的链接过程。为了便于分析LW指令的重定位的过程,ld使用自定义的链接脚本,内容如下:

    // ld.lds
    OUTPUT_ARCH(mips)
    ENTRY(__export_parasite_head_start) /*指定了程序入口函数*/
    SECTIONS
    {
    	. = 0x120000000; /*0xfff70c4000;  指定当前虚拟地址*/
    	tinytext : {  
    		*(.head.text)
            	*(.text*)
    		*(.data)
    		*(.rodata)
    	}
    
    	/DISCARD/ : { /*释义:需要丢弃的输入段*/
    	*(.comment)
    	*(.pdr)
    	}
    
    /* Parasite args should have 4 bytes align, as we have futex inside. */
    . = ALIGN(4);
    __export_parasite_args = .;
    }
    

    在这个文件中,你只要关注两点, 一、"ENTRY(__export_parasite_head_start)"指定了程序运行的入口地址,没有它,接下来的ld命令会失败 。二、". = 0x120000000" 指定了当前虚拟起始地址。接下来执行l命令。

    $ ld -static -T ld.lds -o test test.o
    

    这时查看生成的test文件已经是可执行的,relocation已经完成。

    $ file test
    test: ELF 64-bit LSB executable, MIPS, MIPS64 rel2 version 1 (SYSV), statically linked, not stripped
    

    二、relocation分析

    敲黑板上面的内容都是准备工作,接下来开始分析重定位(relocation)的过程。
    首先反汇编test文件

    $ objdump -D test > test.dump
    

    打开test.dump文件

    test:     文件格式 elf64-tradlittlemips
    	...
    
    Disassembly of section tinytext:
     000000fff70c4030 <__export_parasite_head_start>:
       fff70c4030:   3c040000        lui     a0,0x0
       fff70c4034:   3c01f70c        lui     at,0xf70c
       fff70c4038:   64840100        daddiu  a0,a0,256
       fff70c403c:   0004203c        dsll32  a0,a0,0x0
       fff70c4040:   0081202d        daddu   a0,a0,at
       fff70c4044:   8c84404c        lw      a0,16460(a0)
       fff70c4048:   03e00008        jr      ra
      
     000000fff70c404c <__export_parasite_cmd>:
      fff70c404c:   00000002        srl     zero,zero,0x0
    
    

    发现和上面的test.o文件反汇编文件的不同点了吗?我把区别标记下来并开始分析:
    在这里插入图片描述

    其中蓝色部分是做了重定向的结果。 R_MIPS_HIGHEST、R_MIPS_HI16 、R_MIPS_HIGHER、R_MIPS_LO16是重定位入口类型。每种类型的指令修正方式可以通过查看mipsabi文档可以找到
    目前我从https://elinux.org网站上下载下来的mipsabi.pdf文档里对重定向入口类型介绍的也不全,最好的分析办法是看 binutils 的源码
    还要明确一下,我当前运行的是在龙芯处理器上。mips寄存器为64位,指令32位,寻址48位(我还不确定)。lw指令的描述是 lw rt,offset(base) ,这里base可以寻址64位。按上面的"lw a0,16460(a0)" 为例,base值应该是0xfff70c0000(等于ld.lds里面设置的初始虚拟地址) 。16460是10进制数,对应的16进制数为0x404c。那么寻址后的a0值应该为0xfff70c0000+0x404c = 0xfff70c404c。base值应该是(也就是上面的a0)
    在这里插入图片描述

    接下来我开始分析上面的每一条指令来了解lw a0,__export_parasite_cmd是怎么加载上来的。

    第一条指令 lui a0,0x0

    lui 功能为上位加载立即数,描述为a0 = 0x0<<16位,操作后的a0值为:
    a0 :0x0000 0000 0000 0000

    第二条指令 lui at,0xf70c

    这里使用了at寄存器做中间变量,描述为at = 0xf70c<<16,操作后的at值为:
    at:0xffff ffff f70c 0000
    这里是最让人费解的地方,f70c左移16位后应该是0x0000 0000 f70c 0000。而这里却是0xffff ffff f70c 0000 这是我通过gdb调试确认过的结果,可能是MIPS实现48位内存寻址的策略

    第三条指令 daddiu a0,a0,256

    daddiu 功能为64位立即数加法,描述为a0 = a0+256 ,256为10进制对应0x0100,操作后的a0值为:
    a0:0x0000 0000 0000 0100

    第四条指令 dsll32 a0,a0,0x0

    dsll32 功能为32位左移,描述为a0 = a0<<(32+0x0),操作后的a0值为:
    a0:0x0000 0000 0100 0000

    第五条指令 daddu a0,a0,at

    daddu功能同daddiu,为64位加法,但是操作数不是立即数而是寄存器。描述为a0 = a0+at,结果为:
    a0:0x0000 00ff f70c 0000
    此时你可能明白点为啥at值的高32位填充全f的原因没?

    分析的最后一条 lw a0,16460(a0)

    lw 功能为32位加载,64位CPU上进行符号扩展。 描述为a0 = memory(0xff f70c 0000+0x404c),a0结果为:
    a0 = 2 //如果不信,你可以使用gdb调试
    也就是lw执行后,a0可以加载到内存地址为fff70c404c上的数据。

    到这里,我们已经通过重定位的指令分析了lw的基址计算过程。如果让你去实现relocation过程,你该怎么做?可能我们不被逼到死路是不会考虑这个问题。此刻,我就在死路上。

    敲黑板:指令修正方式

    上面提到了重定位入口类型R_MIPS_HIGHEST、R_MIPS_HI16 、R_MIPS_HIGHER、R_MIPS_LO16,但是分析过程一点没有用到,那是由于ld已经帮我们根据这几个类型实现了指令修正。重定位入口类型只有在test.o 到可执行文件test 的汇编过程才会用到。test.o是ELF格式的文件,ELF格式中会存储哪些段需要重定位以及指令修正的类型等信息。我们可以通过readelf命令查看

    $ readelf -r test.o
    
    重定位节 '.rela.head.text' 位于偏移量 0x4b0 含有 4 个条目:
      Offset          Info           Type           Sym. Value    Sym. Name + Addend
    000000000000  00040000001d R_MIPS_HIGHEST    0000000000000000 .head.text + 1c
                        Type2: R_MIPS_NONE      
                        Type3: R_MIPS_NONE      
    000000000004  000400000005 R_MIPS_HI16       0000000000000000 .head.text + 1c
                        Type2: R_MIPS_NONE      
                        Type3: R_MIPS_NONE      
    000000000008  00040000001c R_MIPS_HIGHER     0000000000000000 .head.text + 1c
                        Type2: R_MIPS_NONE      
                        Type3: R_MIPS_NONE      
    000000000014  000400000006 R_MIPS_LO16       0000000000000000 .head.text + 1c
                        Type2: R_MIPS_NONE      
                        Type3: R_MIPS_NONE      
    

    offset是指当前指令在elf文件中的位置,Type即为重定位入口类型,Addend会参与到指令修正的运算。

    MIPS上的重定位类型对应的计算方式可以通过mipsabs.pdf查看到一些(但不是全部),如下图:
    在这里插入图片描述

    在此我就上面的几个类型结合代码讲解test.o中relocation的计算过程。

    重定位类型 R_MIPS_HIGHEST

    通过elf格式解析过程能够看到test.o中第一条指令 lui a0,0x0 ,指令码为 3c040000,重定位类型为R_MIPS_HIGHEST。怎么计算呢?mipsabi上还真没有,我参考了binutils的源码中mips.cc得出计算过程为:
    ((vbase(0xfff70c4000)+ 0x800080008000llu)>>48) & 0xffff

    上述的计算结果(0x0)放在lui指令的低16位。修正后的lui指令码还是 3c040000

    重定位类型 R_MIPS_HI16

    test.o中第二条指令 lui at,0x0,指令码为 3c010000,重定位类型 R_MIPS_HI16,计算方式根据不同的符号类型有不同的计算方式,此处的符号类型为Local,计算过程为:
    ((vbase(0xfff70c4000)+ 0x8000)>>16) & 0xffff
    上述的计算结果(0xf70c)放在lui指令的低16位,修正后的lui指令码为 3c01f70c

    重定位类型 R_MIPS_HIGHER

    第三条指令 daddiu a0,a0,256 ,指令码为 64840000 ,重定位类型为R_MIPS_HIGHER,计算方式也只能参考binutils的源码中mips.cc文件
    ((vbase(0xfff70c4000)+ 0x80008000)>>32) & 0xffff
    上述计算结果(0x0100)放在daddiu指令的低16位,修正后的daddiu指令码为64840100

    重定位类型 R_MIPS_LO16 ( fixme)

    第六条指令 lw a0,0(a0) ,指令码为 8c840000 ,重定位类型为R_MIPS_LO16,计算方式根据不同的符号类型有不同的计算方式,此处的符号类型为Local,计算过程为:
    (vbase(0xfff70c4000)& 0xffff)+A (0x4c)

    上述计算结果(0x404c)放在lw指令的低16位,修正后的lw指令码为8c84404c

    展开全文
  • MIPS指令集中LB和LW的区别

    千次阅读 2020-04-21 22:46:14
    文章目录LB 取字节LW ...指令如下 内存如下 LB和LW都是取0x7C位置的值,但LB取的是字节,也就是0x80, 然后按照符号扩展,LB得到的值是有符号的0xFF80. 而LW取的是32位的字,即下图中红框中的值: 故LW得到的是...

    LB 取字节

    在这里插入图片描述

    LW 取字

    在这里插入图片描述

    区别

    LB与LW的区别:LB加载字节,地址不一定是4的倍数。LW加载字(1字=4字节),地址必须是4的倍数。

    举例

    指令如下
    在这里插入图片描述
    内存如下
    在这里插入图片描述
    LB和LW都是取0x7C位置的值,但LB取的是字节,也就是0x80,
    在这里插入图片描述
    然后按照符号扩展,LB得到的值是有符号的0xFF80.
    而LW取的是32位的字,即下图中红框中的值:
    在这里插入图片描述
    故LW得到的是有符号的0x0080

    展开全文
  • 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]。

    展开全文
  • MIPS 指令

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

    2021-02-03 10:56:40
    MIPS常用指令集 lb/lh/lw: 从存储器中读取一个byte/half word/word的数据到寄存器中.如lb $1, 0($2) sb/sh/sw: 把一个byte/half word/word的数据从寄存器存储到存储器中.如 sb $1, 0($2) add/addu:把两个定点寄存器...
  • mips指令

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

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 122
精华内容 48
关键字:

lw指令mips