计算机系统(3) 实验一:MIPS64位指令集实验

一、 实验目标:

了解WinMIPS64的基本功能和作用;

熟悉MIPS指令、初步建立指令流水执行的感性认识;

掌握该工具的基本命令和操作,为流水线实验作准备。

二、实验内容

按照下面的实验步骤及说明,完成相关操作记录实验过程的截图

1)下载WinMIPS64;运行样例代码并观察软件各个观察窗口的内容和作用,掌握软件的使用方法。(80分)

2)学会正确使用WinMIPS64的IO方法;(10分)

3)编写完整的排序程序;(10分)

三、实验环境

硬件:桌面PC

软件:Windows,WinMIPS64仿真器

四、实验步骤及说明

WinMIPS64是一款指令集模拟器,它是基于WinDLX设计的,如果你对于WinDLX这款软件十分熟悉的话,那么对于WinMIPS64也会十分的容易上手。DLX 处理器 (发音为 "DeLuXe")是Hennessy 和Patterson合著一书《Computer Architecture - A Quantitative Approach》中流水线处理器的例子。WinDLX是一个基于Windows的模拟器。

本教程通过一个实例介绍WinMIPS64的使用方法。WinMIPS64模拟器能够演示MIPS64流水线是如何工作的。 

本教程使用的例子非常简单,它并没有囊括WinMIPS64的各个方面,仅仅作为使用WinMIPS64的入门级介绍。如果你想自己了解更多的资料,在给出的winmips64.zip中,有WinMIPS64 — Documentation Summary.html和winmipstut.docx两个文件可以供你随时参考,其中涵盖了WinMIPS64的指令集和模拟器的组成与使用方法。

虽然我们将详细讨论例子中的各个阶段,但你应具备基本的使用Windows的知识。现假定你知道如何启动 Windows,使用滚动条滚动,双击执行以及激活窗口。

(一)、安  装

请按以下步骤在Windows下安装WinMIPS64 :

  1. 为WinMIPS64 创建目录,例如D:\ WinMIPS64 
  2. 解压给出的winmips64.zip压缩文件到创建的目录中

本文章主要讲解终端IO的简单操作以及用mips指令完成冒泡排序和快速排序。

用终端输出"Hello World!\n"

实验材料给出的CONTROL值对应的相关功能,这里输出字符串,则让CONTROL赋值为4

 计算机系统(3) 实验一:MIPS64位指令集实验_第1张图片

 代码如下:

.data
CONTROL: .word32 0x10000
DATA:	.word32 0x10008
HW:	.asciiz "Hello World!\n"    //STRING

.text
lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4   ;set  for ascii output
daddi $t1,$zero,HW  ;load String in t1
sd $t1,0($t8)   ;write address of the string to data
sd $v0,0($t9)   ;print

halt

 接下来是一个在终端上输出我们在键盘按下的按键的程序

.data
CONTROL: .word32 0x10000
DATA:	.word32 0x10008

.text
lwu $t9,CONTROL($zero); load Control
lwu $t8,DATA($zero); load DATA
sd $v0,0($t9);  

daddi $t2,$zero,13; 如果按下的按键是回车

LOOP:  daddi $v0,$zero,9;  CONTROL=9
sd $v0,0($t9);  
ld $t1,0($t8);   t1 reads the byte
beq $t1,$t2,OUT;  如果输入的是回车则退出循环
sd $t1,DATA($zero);  将输入的按键保存在DATA区
daddi $v0,$zero,4;  CONTROL=4
daddi $t1,$zero,DATA;
sd $t1,0($t8);
sd $v0,0($t9);  输出
j LOOP;
OUT:  halt;

排序部分:

在这一部分,我们要求编写一个排序算法,对一组int型数据进行排序。该算法使用冒泡排序法,并且在其中嵌入一个swap函数过程(该算法在课本上有完整的程序,但是其中的数据初始化、寄存器映射、命令的映射以及I/O部分还需要自己手动编写)。编写完成后,在asm.exe中进行检测,然后运行。

初始数据要求为:“array: .word 8,6,3,7,1,0,9,4,5,2”

该程序需要对0到10,十个数进行了排序,其中使用了sort和swap两个函数过程,并且swap是嵌套在sort中的,在编写程序的时候一定要注意使用栈来保留寄存器的值,嵌套时还额外需要保存$ra的值。在WinMIPS64运行上述程序,将得到如下结果(这里只给出Terminal窗口的截图即可):

计算机系统(3) 实验一:MIPS64位指令集实验_第2张图片

 冒泡排序:

.data
CONTROL: .word32 0x10000
DATA:	.word32 0x10008
array:  .word   8,6,3,7,1,0,9,4,5,2
before: .asciiz "before sort the array is:\n"
after:  .asciiz "after  sort the array is:\n"
next:   .asciiz "\n"

.text
lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,before;
sd    $t3,0($t8);
sd    $v0,0($t9);   print before...


daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOP:   

ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOP;    
;now start bubble sorting !!!


daddi $t1,$zero,-1;  t1=-1
daddi $t2,$zero,0;

LOOPi:  daddi $t1,$t1,1; t1++  外层for循环
daddi $t2,$t1,1;  j = i + 1 
LOOPj:  dadd $a0,$zero,$t1;   内层for循环
dadd $a1,$zero,$t2;
daddi $t0,$zero,8;
dmul $a0,$t0,$a0;
dmul $a1,$t0,$a1;
jal swap;

BACK:  daddi $t2,$t2,1; t2++
slti $t5,$t2,10;   if j < 10  t5=1
bne $t5,$zero,LOOPj;
slti $t5,$t1,9;  if i < 9 t5=1
bne $t5,$zero,LOOPi;


lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,after;
sd    $t3,0($t8);
sd    $v0,0($t9);   print after...

daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOPPRINT:   ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOPPRINT;    

halt

swap:
ld $s0,array($a0);  交换函数,在这里判断是否交换
ld $s1,array($a1);
slt $t0,$s0,$s1;
bne $t0,$zero,EXIT;
sd $s0,array($a1);  完成交换操作
sd $s1,array($a0);
EXIT:  jr $ra;

其中,这两部分分别是 开始输出和结尾输出,用于在终端上输出。

lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,before;
sd    $t3,0($t8);
sd    $v0,0($t9);   print before...


daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOP:   

ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOP;    
;now start bubble sorting !!!

/
lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,after;
sd    $t3,0($t8);
sd    $v0,0($t9);   print after...

daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOPPRINT:   ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOPPRINT;  

快速排序:

如果本身对快速排序不太了解或根本不了解,建议直接去CSDN看相关的快速排序文章。

附上代码前,先讲解一下快速排序的思想。

快排通过以第一个成员作为哨兵位,分别从第二个往后和最后一个往前找,其中要注意,后向前先,找到一个比哨兵位小的成员然后转为前往后找一个比哨兵位大的数,两数交换,接着继续。结束标志为当双方同时到了同一个数,那么将相遇时候的数与哨兵位交换,然后开启新一轮的循环。

这里附上JAVA的快排代码,下面的mips代码在此基础上构建即可。 

public static void quicksort(int l,int h,int []arr){
        if(h>l){
            int i=l,j=h,flag=0;
            while(iarr[j]){//符合交换条件
                    swap(i,j,arr);
                    if(flag==0){//换方向
                        i++;
                        flag=1;
                    }
                    else{//换方向
                        flag=0;
                        j--;
                    }
                }
                else{
                    if(flag==0)
                        j--;//此时从后往前
                    else
                        i++;//此时从前往后
                }
            }
            quicksort( l,i-1,arr);
            quicksort(  i+1, h,arr);
        }
    }
    public  static void swap(int i,int j,int []arr){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }

mips指令如下: 

.data
CONTROL: .word32 0x10000
DATA:	.word32 0x10008
array:  .word   8,6,3,7,1,0,9,4,5,2
before: .asciiz "before sort the array is:\n"
after:  .asciiz "after  sort the array is:\n"
next:   .asciiz "\n"


.text
lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,before;
sd    $t3,0($t8);
sd    $v0,0($t9);   print before...


daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOP:   

ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOP;    
;now start bubble sorting !!!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
daddi $t4,$zero,0;
daddi $t5,$zero,0;clear t4andt5
;;$a0=l $a1=h   quicksort(0,9)
daddi $a0,$zero,0;
daddi $a1,$zero,9;
daddi $sp,$zero,0x3f8;
jal QSORT;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lwu $t8,DATA($zero) ;store DATA in t8
lwu $t9,CONTROL($zero);store CONTROL in t9
daddi $v0,$zero,4;
daddi $t3,$zero,after;
sd    $t3,0($t8);
sd    $v0,0($t9);   print after...

daddi $t2,$zero,10;set t2=10,t2 counts whether is 0
daddi $t1,$zero,0;set t1 = 0
LOOPPRINT:   ld $t4,array($t1)
daddi $v0,$zero,2;
sd $t4,0($t8);
sd $v0,0($t9);
daddi $t1,$t1,8; t1+=8
daddi $t2,$t2,-1; t2=-1;
bne $t2,$zero,LOOPPRINT;  


halt;


QSORT:  daddi $sp,$sp,-24;  a0=l,a1=h
sd $ra,0($sp);
sd $a0,8($sp);
sd $a1,16($sp);

slt $t0,$a0,$a1; if ll)
beq $t0,$zero,OUT; if t0==0,end;

dadd $s0,$zero,$a0; s0=i 
dadd $s1,$zero,$a1; s1=j
daddi $s2,$zero,0; s2=flag=0;

WHILE:  slt $t0,$s0,$s1;if i

相关说明:

前面的输出和结尾的输出功能前面讲过了,这里不再提。

 在调用QSORT函数之前,先清空了前面对$t4 $t5寄存器的影响。

对将要转递的参数$a0 $a1初始化,

下面注意对$sp 寄存器的操作,让$sp加上了0x3f8

daddi $t4,$zero,0;
daddi $t5,$zero,0;clear t4andt5
;;$a0=l $a1=h   quicksort(0,9)
daddi $a0,$zero,0;
daddi $a1,$zero,9;
daddi $sp,$zero,0x3f8;
jal QSORT;

0x03f8是data窗口能看到的最后一个地址

让$sp寄存器初始化到最后一个地址,之后每次存值的时候都是从最后往上存,可以保证存的数据有效且可视。

如果没有初始化的话,$sp寄存器默认为0,那么将无法保存数据并且无法看到后续的存值情况

计算机系统(3) 实验一:MIPS64位指令集实验_第3张图片

 在调用快速排序后,一进入函数里,先保存参数和返回地址进内存里面。因为这里是64位的系统,所以寄存器需要8个字节存放。

完成函数即将返回前,需要取出之前存放在内存中的数值。

QSORT:  daddi $sp,$sp,-24;  a0=l,a1=h
sd $ra,0($sp);
sd $a0,8($sp);
sd $a1,16($sp);
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\\PROCEDURE
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
OUT:  ld $a1,16($sp);
ld $a0,8($sp);
ld $ra,0($sp);
daddi $sp,$sp,24;
jr $ra;

 SWAP函数进行了优化,减少了代码量。

传递参数的时候就让两个参数*8操作,之后在SWAP函数里面可以直接用参数获取到数组成员

daddi $t7,$zero,8;
dmul $t1,$s0,$t7; t1=[i]
dmul $t2,$s1,$t7; t2=[j]
dadd $a0,$t1,$zero;  a0=[i]
dadd $a1,$t2,$zero;  a1=[j]
jal SWAP;   swap(i,j)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
SWAP:  ld $s3,array($a0); s3=temp=a[i]
ld $t0,array($a1);
sd $t0,array($a0); a[i]=a1=a[j]
sd $s3,array($a1); a[j]=s0=temp
jr $ra;

如有不懂的地方,可以在留言区咨询博主! 

你可能感兴趣的:(计算机系统(3),windows)