计算机系统结构
计算机系统结构的经典定义为程序员所看到的计算机属性,即概念性结构与功能特性。按照计算机系统的多级层次结构,不同级程序员所看到的计算机具有不同的属性。
在计算机系统结构中有个较为经典的实验:在windlx模拟器下实现矩阵相乘。这篇文章将从头说起,教大家完成矩阵相乘实验。
由于windlx模拟器的古老性,只能在比较古老的系统上使用,而目前许多人的电脑都是win10系统,所以我们需要装个虚拟机,在虚拟机上使用windows xp或者windows7来运行windlx模拟器。
虚拟机安装
这里用的虚拟机为:VMware-workstation. 网盘链接在下面,大家可以直接点进去下载虚拟机。安装也很简单,按照步骤一步一步来即可。
链接:https://pan.baidu.com/s/1HfPZGa8tkrWDYpetp2jTAw
提取码:hnlh
在安装vm workstation完成之后,需要输入产品序号,直接打开网盘文件中的vm10keygen ,复制上面的serial,此即为产品序号,之后便可正常使用。
安装vm workstation成功之后,打开界面如下。直接点击打开虚拟机,再装入镜像即可。
windlx使用
在虚拟机安装成功的情况下,便可以在虚拟机中安装windlx模拟器了。windlx模拟器文件在下面:
链接:https://pan.baidu.com/s/1MnerlQl2oxpijvQtU3DYRQ
提取码:bqvq
在虚拟机上安装windlx模拟器十分简单,你可以选择直接将windlx文件拖进虚拟机屏幕内即可。
打开实验平台文件,直接点击windlx.exe启动即可。
矩阵相乘实验
在安装完虚拟机与windlx模拟器之后,我们就可以开始矩阵相乘实验啦。
步骤如下:
- File->reset DLX->确定
- File->Load code or data->双击martrix.s->双击input.s->load->是
ATTENTION 此步骤很重要,必须要先点击martrix.s再点击input.s,否则在后面运算的时候会出现wrong address错误。
- 接下来就可以直接计算啦!!!
- execute->run->输入各种数值
下图为最终的计算结果~
在Code窗口中,我们能够看到代表存储器内容的三栏信息,从左到右依次为:地址 (符号或数字)、命令的十六进制机器代码和汇编命令。
寄存器Rigster图如下:
Register 窗口会显示各个寄存器中的内容。
在Statistisc中得到结果如下所示
Statistics 窗口提供各个方面的信息:模拟中硬件配置情况、暂停及原因、条件分支、 Load/Store指令、浮点指令和traps。窗口中给出事件发生的次数和百分比.
流水线PipeLine窗口如下:
下图显示了DLX处理器的五个流水段和浮点操作 (加 / 减, 乘和除)的单元。
时钟周期Clock Cycle Diagram窗口显示流水线时空图如下:
好啦!矩阵相乘实验到这里就完成了,最后附上martrix.s文件的代码,想修改代码时可以直接用记事本打开Martrix.s文件直接改即可。
程序代码如下:
;***********multiply an array to an array *************
;*********** *************
;------------------------------------------------------------------------
; Program begins at symbol main
; requires module INPUT
; Read two arrays, calculate the multiplition of two arrays
; and write the result to stdout
;------------------------------------------------------------------------
.data
;*** Prompts for input输入提示部分
dat1: .space 64
dat2: .space 64
result: .space 64
Prompt1: .asciiz "Input the martrixA row:"
Prompt2: .asciiz "Input the martrixA column and the martrixB row: "
Prompt3: .asciiz "Input the martrixB column:"
Prompt4: .asciiz "Input the martrixA's number:"
Prompt5: .asciiz "Input the martrixB's number:"
Prompt6: .asciiz "IF you want to run it again (no=0, other continue):"
;*** Data for printf-Trap ;输出数据设置部分
PrintfFormat: .asciiz "%5.3d "
.align 2
PrintfPar: .word PrintfFormat
PrintfValue: .space 4
PrintfFormat1: .asciiz "\n "
.align 2
PrintfPar1: .word PrintfFormat1
PrintfValue1: .space 4
PrintfFormat2: .asciiz "Output the martrixA:\n "
.align 2
PrintfPar2: .word PrintfFormat2
PrintfValue2: .space 4
PrintfFormat3: .asciiz "Output the martrixB:\n "
.align 2
PrintfPar3: .word PrintfFormat3
PrintfValue3: .space 4
PrintfFormat4: .asciiz "The result of martrix A*B:\n "
.align 2
PrintfPar4: .word PrintfFormat4
PrintfValue4: .space 4
.text
.global main
main: addi r1,r0,Prompt1
jal InputUnsigned
movi2fp f1,r1 ;矩阵A的行数
addi r1,r0,Prompt2
jal InputUnsigned
movi2fp f2,r1 ;矩阵A的列数,矩阵B的行数
addi r1,r0,Prompt3
jal InputUnsigned
movi2fp f3,r1 ;矩阵B的列数
movfp2i r8,f1
movfp2i r6,f2
multu r4,r6,r8 ;总的矩阵A的元素个数r4
addi r2,r10,dat1 ;指向A的首地址
loop1: add r1,r0,Prompt4 ;分别读入矩阵A的元素值
jal InputUnsigned
sb 0(r2),r1 ;储存字节,读入元素
addi r2,r2,1 ;元素个数加一
sub r4,r4,1 ;总的矩阵元素个数r4减一
bnez r4,loop1 ;r4不为0时跳转重复输入
addi r10,r0,0 ;分别读出矩阵A的元素值
addi r2,r10,dat1 ;指向A的首地址
sw PrintfValue2,r1
addi r14,r0,PrintfPar2
trap 5
loopA: lbu r1,0(r2)
sw PrintfValue,r1
addi r14,r0,PrintfPar ;换行
trap 5
addi r2,r2,1 ;元素个数加一
sub r6,r6,1 ;矩阵A的列数r6减一
beqz r6,outputA ;矩阵A的列数r6等于0时跳到outputA
j loopA ;否则继续loopA
outputA: sw PrintfValue1,r1
addi r14,r0,PrintfPar1
trap 5
sub r8,r8,1 ;矩阵A的行数r8减一
beqz r8,countiuB ;矩阵A的行数r8等于0时跳到countiuB
movfp2i r6,f2
j loopA ;否则继续loopA
countiuB: movfp2i r6,f2
movfp2i r12,f3
addi r10,r0,0
multu r4,r6,r12 ;总的矩阵B的元素个数r4
addi r2,r10,dat2 ;指向B的首地址
loop2: addi r1,r0,Prompt5 ;分别读入矩阵B的元素值
jal InputUnsigned
sb 0(r2),r1 ;储存字节,读入元素
addi r2,r2,1 ;元素个数加一
sub r4,r4,1 ;总的矩阵元素个数r4减一
bnez r4,loop2 ;r4不为0时跳转重复输入
addi r10,r0,0 ;分别读出矩阵B的元素值
addi r2,r10,dat2 ;指向B的首地址
sw PrintfValue3,r1
addi r14,r0,PrintfPar3
trap 5
loopB: lbu r1,0(r2)
sw PrintfValue,r1
addi r14,r0,PrintfPar ;换行
trap 5
addi r2,r2,1 ;元素个数加一
sub r12,r12,1 ;矩阵B的列数r12减一
beqz r12,outputB ;矩阵B的列数r12等于0时跳到outputB
j loopB ;否则继续loopB
outputB: sw PrintfValue1,r1
addi r14,r0,PrintfPar1
trap 5
sub r6,r6,1 ;矩阵B的行数r6减一
beqz r6,countiue ;矩阵B的行数r6等于0时跳到countiu
movfp2i r12,f3
j loopB ;否则继续loopB
countiue: addi r11,r0,0 ;temp,表示矩阵C的一个元素的累加器
addi r4,r0,0 ;r 初始化矩阵C的偏移量
addi r5,r0,0 ;矩阵A当前被扫描的行号
line: movi2fp f4,r5 ;判断是否扫描完
ltf f4,f1 ;f4>f1跳转(矩阵A的行是否扫描完)
bfpf finish ;是,则跳转结束程序
addi r6,r0,0 ;col,r6表示当前B矩阵的列号
column: movi2fp f4,r6
ltf f4,f3 ;col(f3)<f4,矩阵B的列是否扫描完
bfpf leveladd ;是,则跳到矩阵a的下一行
movfp2i r1,f2
multu r10,r5,r1 ;i<-l*n,r10表示矩阵A当前行的第一个元素的索引
addi r7,r6,0 ;mov col to j(矩阵B某一列的某个元素的索引)
addi r11,r0,0 ;temp=0,矩阵C当前的元素值的初始化
addi r9,r5,1 ;r9<-l+1,r9代表矩阵A当前数组中的实际行号(r5的初值为0)
movfp2i r1,f2 ;f2是矩阵A的列数
multu r9,r1,r9 ;p<-n*(l+1),r9代表矩阵A当前行中最后一个元素在数组中的索引
calculate:movi2fp f4,r10
movi2fp f9,r9
ltf f4,f9 ;compare i to pz(判断是否计算到当前行的最后一个元素)
bfpf asign ;当前行列相乘完毕,得出结果矩阵C的一个元素(跳转赋值)
addi r1,r10,dat1 ;取矩阵A当前元素在内存区域中的地址
lbu r2,0(r1) ;从r1所指向的内存单元中取出矩阵A当前的元素暂存在r2
addi r1,r7,dat2 ;取矩阵B当前元素在内存区域中的地址
lbu r3,0(r1) ;从r1所指向的内存单元中取出矩阵B当前的元素暂存在r3
multu r1,r2,r3 ;temp1<-dat1[i]+dat2[j]
add r11,r11,r1 ;temp<-temp+temp1,累加到累加器
addi r10,r10,1 ;i++,计算矩阵A当前行的下个元素的索引
movfp2i r1,f3
add r7,r7,r1 ;j<-j+k,计算矩阵B的当前列的下个元素的索引
j calculate
asign: addi r1,r4,result ;r1表示矩阵C当前的地址
sb 0(r1),r11 ;store result,把新计算出来的元素放入当前内存单元
addi r4,r4,1 ;赋值完一个元素,偏移量自增1
addi r6,r6,1 ;矩阵B的当前列数自增1
j column ;矩阵B新的一列开始
leveladd: addi r5,r5,1 ;矩阵A当前行自增1
j line ;矩阵A新的一行开始
finish: addi r10,r0,0 ;分别读出矩阵C的元素值
movfp2i r8,f1
movfp2i r12,f3
addi r2,r10,result
sw PrintfValue4,r1
addi r14,r0,PrintfPar4
trap 5
loop3: lbu r1,0(r2)
sw PrintfValue,r1
addi r14,r0,PrintfPar
trap 5
addi r2,r2,1
sub r12,r12,1
beqz r12,outputC
j loop3
outputC: sw PrintfValue1,r1
addi r14,r0,PrintfPar1
trap 5
sub r8,r8,1
beqz r8,choice
movfp2i r12,f3
j loop3 ;*** end
choice:add r1,r0,Prompt6 ;是否重复本次运行操作
jal InputUnsigned
beqz r1,end ;若为0则结束运行
j main ;否则则重复执行
end: trap 0
``