Merge pull request 'Submit HW1' (#1) from HW1 into main

Reviewed-on: #1
This commit is contained in:
2024-05-04 15:05:22 +08:00
30 changed files with 1511 additions and 1 deletions

5
.gitignore vendored
View File

@@ -2,3 +2,8 @@
*.pdf
*/attachment/
*.docx
*.out
*.aux
*.log
*.synctex(busy)
*.synctex.gz

7
1/README.txt Normal file
View File

@@ -0,0 +1,7 @@
汇编大作业说明文档.docx 本次作业的具体内容说明
汇编实验指导.pdf 为MIPS重点内容复习及大作业解释
example/ “MARS环境安装与基础使用方法”部分参考代码
exp1/ 作业“第一部分:基础练习”参考代码和样例数据
exp2/ 作业“第二部分:实战应用”参考代码和样例数据
attachment/ 实验用附件
reference/ 参考文献

BIN
1/example/example.in Normal file

Binary file not shown.

BIN
1/example/example.out Normal file

Binary file not shown.

58
1/example/example_0.asm Normal file
View File

@@ -0,0 +1,58 @@
.data
in_buff: .space 512
out_buff: .space 512
input_file: .asciiz "example.in"
output_file: .asciiz "example.out"
comma: .asciiz ", "
.text
la $a0, input_file #input_file <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
li $a1, 0 #flag 0Ϊ<EFBFBD><EFBFBD>ȡ 1Ϊд<EFBFBD><EFBFBD>
li $a2, 0 #mode is ignored <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ0<EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
li $v0, 13 #13 Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall # <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򿪳ɹ<EFBFBD> <EFBFBD><EFBFBD> <EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>$v0<EFBFBD><EFBFBD>
move $a0,$v0 # <EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> $a0<EFBFBD><EFBFBD>
la $a1, in_buff #in_buff Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>
li $a2, 512 #<EFBFBD><EFBFBD>ȡ512<EFBFBD><EFBFBD>byte
li $v0, 14 #14 Ϊ<EFBFBD><EFBFBD>ȡ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall
li $v0 16 #16 Ϊ<EFBFBD>ر<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall
#<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵΪN
la $s0, in_buff
la $s1, out_buff
lw $s2, 0($s0)
li $t0, 0
#<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD>4 ѭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1
for: addi $s0, $s0, 4
addi $t0, $t0, 1
lw $t1, 0($s0)
sw $t1, 0($s1)
addi $s1, $s1, 4
#<EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
move $a0, $t1
li $v0, 1
syscall
#<EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
la $a0, comma
li $v0, 4
syscall
bne $t0 $s2 for
la $a0, output_file #output_file <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
li $a1, 1 #flag 0Ϊ<EFBFBD><EFBFBD>ȡ 1Ϊд<EFBFBD><EFBFBD>
li $a2, 0 #mode is ignored <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ0<EFBFBD>Ϳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
li $v0, 13 #13 Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall # <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򿪳ɹ<EFBFBD> <EFBFBD><EFBFBD> <EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>$v0<EFBFBD><EFBFBD>
move $a0,$v0 # <EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> $a0<EFBFBD><EFBFBD>
la $a1, out_buff #in_buff Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>
sll $s2 $s2 2
move $a2, $s2 #д<EFBFBD><EFBFBD>512<EFBFBD><EFBFBD>byte
li $v0, 15 #15 Ϊд<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall
#<EFBFBD><EFBFBD>ʱ$a0 <EFBFBD>е<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD>
#ֱ<EFBFBD>ӵ<EFBFBD><EFBFBD><EFBFBD> syscall 16 <EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD>
li $v0 16 #16 Ϊ<EFBFBD>ر<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> syscall <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
syscall

12
1/example/example_1.asm Normal file
View File

@@ -0,0 +1,12 @@
.data
.a
string: .asciiz "Hello World!\n"
.text
main:
la $a0 string #
li $v0 4 #4
syscall #
li $v0 17 #17exit
syscall #

50
1/example/example_2.asm Normal file
View File

@@ -0,0 +1,50 @@
.data
stringz: .asciiz "Hello World!\n"
string: .ascii "Hello World!\n"
#array对齐到4byte边界
.align 4 #
array: .space 512
#
barray: .byte 1,2,3,4
harray: .half 1,2,3,4
warray: .word 1,2,3,4
.text
main:
la $a0 stringz #
li $v0 4 #4
syscall #
la $a0 string #
li $v0 4 #4
syscall #
la $t0 barray #byte
lb $a0 0($t0) #barray[0]
li $v0 1 #1
syscall #array[0]
lb $a0 1($t0) #barray[1]
li $v0 1 #1
syscall #array[0]
lb $a0 2($t0) #barray[2]
li $v0 1 #1
syscall #array[0]
lb $a0 3($t0) #barray[3]
li $v0 1 #1
syscall #array[0]
li $a0 10 #10'\n'
li $v0 11 #11
syscall #
la $t0 array #array的地址
li $t1 123
sw $t1 0($t0) #array[0]123
lw $a0 0($t0) #array[0]
li $v0 1 #1
syscall #array[0]
li $v0 17 #17exit
syscall #

35
1/example/example_3.asm Normal file
View File

@@ -0,0 +1,35 @@
.text
main:
li $v0 5 #5
syscall #ִ
move $a0 $v0 #
li $v0 5 #5
syscall #ִ
move $a1 $v0 #
jal product #product
move $a0 $v0 #$a0
li $v0 1 #1
syscall #ִ
li $v0 17 #17exit
syscall #ִ
product:
move $t0 $a0 #t0作为累加值
move $t1 $a1 #t1作为计数器
move $t2 $zero#结果清零
addi $sp $sp -16 #
sw $t0 12($sp) #t0
sw $t1 8($sp) #t1
sw $t2 4($sp) #t2
sw $ra 0($sp) #
loop: add $t2 $t2 $t0 #t0
sw $t2 4($sp) #t2
addi $t1 $t1 -1 #
sw $t1 8($sp) #t2
bnez $t1 loop #0
move $v0 $t2 #
lw $ra 0($sp) #
jr $ra #

BIN
1/exp1/a.in Normal file

Binary file not shown.

18
1/exp1/exp1_1.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "stdio.h"
int main() {
FILE *infile ,*outfile;
int i;
int *buffer;
buffer = new int[2];
infile = fopen("a.in", "rb");
fread(buffer, 4, 2, infile);
fclose(infile);
outfile = fopen("a.out", "wb");
fwrite(buffer, 4, 2, outfile);
fclose(outfile);
scanf("%d", &i);
i = i + 10;
printf("%d", i);
return 0;
}

12
1/exp1/exp1_2.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "stdio.h"
int main() {
int i, j, temp;
scanf("%d", &i);
scanf("%d", &j);
i = -i;
if(j < 0) j = -j;
for(temp = 0; temp < j; ++temp) i += 1;
printf("%d",i);
return 0;
}

15
1/exp1/exp1_3.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "stdio.h"
int main() {
int *a, n, i, t;
scanf("%d", &n);
a = new int [n];
for(i = 0; i < n; i++) scanf("%d",&a[i]);
for(i = 0; i < n / 2; i++) {
t = a[i] + 1;
a[i] = a[n - i - 1] + 1;
a[n - i - 1] = t;
}
for(i = 0;i < n; i++) printf("%d", a[i]);
return 0;
}

18
1/exp1/exp1_4.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "stdio.h"
int Hanoi(int n)
{
if (n == 1) { // 基准情形
return 1;
} else { // 递归情形
return 2 * Hanoi(n - 1) + 1;
}
}
int main()
{
int n;
scanf("%d", &n);
printf("%d", Hanoi(n));
return 0;
}

BIN
1/exp2/a.in Normal file

Binary file not shown.

View File

@@ -0,0 +1,58 @@
#include "stdio.h"
/*
二分插入排序:通过二分查找找到插入位置,然后将元素插入到指定位置。
*/
// 统计待排序数据的比较次数
int compare_count = 0;
// 递归二分查找插入位置
int binary_search(int v[], int left, int right, int n)
{
if (left > right)
return left; // 递归边界,此处不统计比较次数
int mid = (left + right) >> 1;
compare_count++; // 统计比较次数
if (v[mid] > v[n])
return binary_search(v, left, mid - 1, n);
else
return binary_search(v, mid + 1, right, n);
}
// 将新的元素插入到指定位置,并将后续元素后移
void insert(int *v, int k, int n)
{
int i;
int tmp = v[n];
for (i = n - 1; i >= k; i--)
{
v[i + 1] = v[i];
}
v[k] = tmp;
}
void binary_insertion_sort(int v[], int n)
{
int i;
for (i = 1; i < n; i++)
{ // 从第二个元素开始,依次插入到前面已经排好序的序列中
int place = binary_search(v, 0, i - 1, i);
insert(v, place, i);
}
}
int main()
{
FILE *infile, *outfile;
int buffer[1001];
infile = fopen("a.in", "rb");
fread(buffer, 4, 1001, infile);
fclose(infile);
int N = buffer[0];
binary_insertion_sort(&(buffer[1]), N);
buffer[0] = compare_count;
outfile = fopen("a.out", "wb");
fwrite(buffer, 4, N + 1, outfile);
fclose(outfile);
return 0;
}

59
1/exp2/insert_sort.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include "stdio.h"
/*
插入排序:将一个元素插入到一个已经排好序的序列中,使得序列依然有序。
*/
// 统计比较次数
int compare_count = 0;
// 从后往前查找第一个比v[n]小的元素,其后一个位置即为插入位置
int search(int v[], int n)
{
int i;
int tmp = v[n];
for (i = n - 1; i >= 0; i--)
{
compare_count++; // 统计比较次数
if (v[i] <= tmp)
break;
}
return i + 1;
}
// 将新的元素插入到指定位置,并将后续元素后移
void insert(int *v, int k, int n)
{
int i;
int tmp = v[n];
for (i = n - 1; i >= k; i--)
{
v[i + 1] = v[i];
}
v[k] = tmp;
}
void insertion_sort(int v[], int n)
{
int i;
for (i = 1; i < n; i++)
{ // 从第二个元素开始,依次插入到前面已经排好序的序列中
int place = search(v, i);
insert(v, place, i);
}
}
int main()
{
FILE *infile, *outfile;
int buffer[1001];
infile = fopen("a.in", "rb");
fread(buffer, 4, 1001, infile);
fclose(infile);
int N = buffer[0];
insertion_sort(&(buffer[1]), N);
buffer[0] = compare_count;
outfile = fopen("a.out", "wb");
fwrite(buffer, 4, N + 1, outfile);
fclose(outfile);
return 0;
}

121
1/exp2/merge_sort.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "stdio.h" /*
链表的归并排序的核心是将链表分成前后两段分别排序后对两个有序链表归并递归边界是当前链表长度为1。
*/
int compare_count = 0;
// 两个有序链表合并 将右链元素插入到左链中 。
int *merge(int *l_head, int *r_head)
{
// 这里构建一个虚拟头结点 方便在第一个元素前插入 。
int *head = new int[2];
head[1] = (int)l_head;
int *p_left = head;
int *p_right = r_head;
do
{
do
{ // 寻找左链中的插入位置
if (p_left[1] == (int)NULL)
break;
// count the number of comparisons
compare_count++;
if (((int *)p_left[1])[0] > p_right[0])
break;
p_left = (int *)p_left[1];
} while (1);
// 如果到达左链尾端 右链直接接上
if (p_left[1] == (int)NULL)
{
p_left[1] = (int)p_right;
break;
}
int *p_right_temp = p_right;
do
{ // 寻找右链待插入片段
if (p_right_temp[1] == (int)NULL)
break;
// count the number of comparisons
compare_count++;
if (((int *)p_right_temp[1])[0] > ((int *)p_left[1])[0])
break;
p_right_temp = (int *)p_right_temp[1];
} while (1);
// 完成插入操作
int *temp_right_pointer_next = (int *)p_right_temp[1];
p_right_temp[1] = p_left[1];
p_left[1] = (int)p_right;
p_left = p_right_temp;
p_right = temp_right_pointer_next;
if (p_right == NULL)
break;
} while (1);
int rv = head[1];
delete head;
return (int *)rv;
}
// 归并排序主函数 先找链表中点 再分别排序 最后归并
int *msort(int *head)
{
if (head[1] == (int)NULL)
return head;
int *stride_2_pointer = head;
int *stride_1_pointer = head;
do
{ // 通过同时进行步长为 1 和步长为 2 的跳转找中点
if (stride_2_pointer[1] == (int)NULL)
break;
stride_2_pointer = (int *)stride_2_pointer[1];
if (stride_2_pointer[1] == (int)NULL)
break;
stride_2_pointer = (int *)stride_2_pointer[1];
stride_1_pointer = (int *)stride_1_pointer[1];
} while (1);
// 拆成两个链表分别排序 再归并 。
stride_2_pointer = (int *)stride_1_pointer[1];
stride_1_pointer[1] = (int)NULL;
int *l_head = msort(head);
int *r_head = msort(stride_2_pointer);
return merge(l_head, r_head);
}
int main()
{
FILE *infile, *outfile;
int buffer[1001];
infile = fopen("a.in", "rb");
fread(buffer, 4, 1001, infile);
fclose(infile);
int N = buffer[0];
// create a linked list
int *head = new int[2];
head[1] = (int)NULL;
int *pointer = head;
for (int idx = 1; idx <= N; idx++)
{
pointer[1] = (int)new int[2];
pointer = (int *)pointer[1];
pointer[0] = buffer[idx];
pointer[1] = (int)NULL;
}
// sort
head[1] = (int)msort((int *)head[1]);
pointer = head;
outfile = fopen("a.out", "wb");
// 输出比较次数
fwrite(&compare_count, 4, 1, outfile);
// wirte the sorted list to file
do
{
pointer = (int *)pointer[1];
if (pointer == NULL)
break;
fwrite(pointer, 4, 1, outfile);
} while (1);
fclose(outfile);
// 本文件用于翻译,没有释放链表内存的操作
return 0;
}

View File

@@ -0,0 +1,135 @@
#include "stdio.h" /*
链表的归并排序的核心是将链表分成前后两段分别排序后对两个有序链表归并递归边界是当前链表长度为1。
!!!注意:此代码为可运行版本,目的是让大家检验自己的实验结果是否正确
其中的链表节点是通过结构体实现的实际汇编的实现中指针也是32位整数请参考另一个版本的代码merge_sort.cpp
*/
// 统计待排序数据的比较次数
int compare_count = 0;
// 链表节点, 结构体实现
struct Node
{
int value;
Node *next;
};
// 两个有序链表合并,将右链元素插入到左链中 。
Node *merge(Node *l_head, Node *r_head)
{
// 这里构建一个虚拟头结点,方便在第一个元素前插入。
Node *head = new Node;
head->next = l_head;
Node *p_left = head;
Node *p_right = r_head;
do
{
do
{ // 寻找左链中的插入位置
if (p_left->next == (int)NULL)
break;
compare_count++; // 统计比较次数
if ((p_left->next)->value > p_right->value)
break;
p_left = p_left->next;
} while (1);
// 如果到达左链尾端,右链直接接上
if (p_left->next == NULL)
{
p_left->next = p_right;
break;
}
Node *p_right_temp = p_right;
do
{ // 寻找右链待插入片段
if (p_right_temp->next == NULL)
break;
compare_count++; // 统计比较次数
if ((p_right_temp->next)->value > (p_left->next)->value)
break;
p_right_temp = p_right_temp->next;
} while (1);
// 完成插入操作
Node *temp_right_pointer_next = p_right_temp->next;
p_right_temp->next = p_left->next;
p_left->next = p_right;
p_left = p_right_temp;
p_right = temp_right_pointer_next;
if (p_right == NULL)
break;
} while (1);
Node *rv = head->next;
delete head;
return rv;
}
// 归并排序主函数,先找链表中点,再分别排序,最后归并
Node *msort(Node *head)
{
if (head->next == NULL)
return head;
Node *stride_2_pointer = head;
Node *stride_1_pointer = head;
do
{ // 通过同时进行步长为 1 和步长为 2 的跳转找中点
if (stride_2_pointer->next == NULL)
break;
stride_2_pointer = stride_2_pointer->next;
if (stride_2_pointer->next == NULL)
break;
stride_2_pointer = stride_2_pointer->next;
stride_1_pointer = stride_1_pointer->next;
} while (1);
// 拆成两个链表分别排序 再归并 。
stride_2_pointer = stride_1_pointer->next;
stride_1_pointer->next = NULL;
Node *l_head = msort(head);
Node *r_head = msort(stride_2_pointer);
return merge(l_head, r_head);
}
int main()
{
FILE *infile, *outfile;
int buffer[1001];
infile = fopen("a.in", "rb");
fread(buffer, 4, 1001, infile);
fclose(infile);
int N = buffer[0];
Node *head = new Node;
head->next = NULL;
Node *pointer = head;
for (int idx = 1; idx <= N; idx++)
{
pointer->next = new Node;
pointer = pointer->next;
pointer->value = buffer[idx];
pointer->next = NULL;
}
// 排序
head->next = msort(head->next);
// 输出到文件
pointer = head;
outfile = fopen("a.out", "wb");
// 输出比较次数
fwrite(&compare_count, 4, 1, outfile);
do
{
pointer = pointer->next;
if (pointer == NULL)
break;
fwrite(&(pointer->value), 4, 1, outfile);
} while (1);
fclose(outfile);
// 释放链表内存
while (head != NULL)
{
Node *temp = head;
head = head->next;
delete temp;
}
return 0;
}

BIN
1/homework/exp1/a.in Normal file

Binary file not shown.

BIN
1/homework/exp1/a.out Normal file

Binary file not shown.

View File

@@ -0,0 +1,42 @@
.data
file_buff: .space 8 # A space of 2 bytes
.align 3
input_file_name: .asciiz "a.in"
.align 3
output_file_name: .asciiz "a.out"
.align 3
.text
la $a0, input_file_name
li $a1, 0 # set mode as read
li $a2, 0 # meaning nothing, really
li $v0, 13 # open file
syscall #now $v0 is the file handler
move $a0, $v0 #move file handler to a0 as first syscall arg
la $a1, file_buff
li $a2, 8 # read in 8 bytes
li $v0, 14
syscall
li $v0, 16
syscall # close file
la $a0, output_file_name
li $a1, 1 # set mode as write
li $a2, 0 # meaning nothing, really
li $v0, 13 # open file
syscall
move $a0, $v0
la $a1, file_buff
li $a2, 8 # write 8 bytes
li $v0, 15 # write file
syscall
li $v0, 16
syscall
li $v0, 5 # read integer
syscall
addi $a0, $v0, 10 # a0 = v0 + 10
li $v0, 1 # print integer
syscall

View File

@@ -0,0 +1,29 @@
.data
.text
li $v0, 5 # read in i
syscall
move $s1, $v0 # use s1 to store i
li $v0, 5 # read in j
syscall
move $s2, $v0 # use s2 to store j
sub $s1, $zero, $s1 # i = -i
bgez $s2, no_neg_j # if >= 0, then no neg
sub $s2, $zero, $s2 # j = -j
no_neg_j:
move $s0, $zero # use s0 as temp, temp = 0
count_up_j:
bge $s0, $s2, done_count_up # if temp >= j, stop iteration
addi $s1, $s1, 1 # i = i + 1
addi $s0, $s0, 1 # ++temp
j count_up_j
done_count_up:
move $a0, $s1
li $v0, 1
syscall
move $v0, $s1 # set return value

View File

@@ -0,0 +1,67 @@
.data
.text
li $v0, 5 # read in num
syscall
move $s0, $v0 # $s0 is n
sll $a0, $v0, 2
li $v0, 9 # malloc
syscall
move $s1, $v0 # $s1 = a
move $t0, $zero # a0 = 0
move $t0, $zero # i = 0
move $t1, $s1 #t1 = a
read_in_num:
bge $t0, $s0, done_read_in_num # i >= n, break
li $v0, 5 # read in num
syscall
sw $v0, 0($t1) # a[i] = v0
addi $t0, $t0, 1 # i++
addi $t1, $t1, 4 # t1 += 4
j read_in_num
done_read_in_num:
srl $s2, $s0, 1 # s1 = n / 2
move $t0, $zero # i = 0
move $t1, $s1
subi $t2, $s0, 1 # t2 = n - 1
sll $t2, $t2, 2 # t2 *= 4
add $t2, $t2, $s1
reverse:
bge $t0, $s2, done_reverse # i >= n / 2, break
lw $t3, 0($t1) # t3 = a[i]
addi $t3, $t3, 1 # t3 += 1
lw $t4, 0($t2) # t4 = a[n - i - 1]
addi $t4, $t4, 1 # t4 += 1
sw $t4, 0($t1)
sw $t3, 0($t2)
addi $t0, $t0, 1
addi $t1, $t1, 4
subi $t2, $t2, 4
j reverse
done_reverse:
move $t0, $zero
move $t1, $s1
output:
bge $t0, $s0, done_output
lw $a0, 0($t1)
li $v0, 1
syscall
addi $t0, $t0, 1
addi $t1, $t1, 4
j output
done_output:
li $a0, 0
li $v0, 17
syscall

View File

@@ -0,0 +1,36 @@
.data
.text
main:
li $v0, 5 # read in
syscall
move $s0, $v0 # s0 is the n
move $a0, $s0 # set the first call arg as n
jal hanoi # call proc
move $a0, $v0 # print out
li $v0, 1
syscall
li $a0, 0
li $v0, 17
syscall
hanoi:
li $t0, 1
ble $a0, $t0, hanoi_bottom # if n <= 1, return
j hanoi_recur
hanoi_bottom:
li $v0, 1 # return 1
jr $ra
hanoi_recur:
subi $sp, $sp, 8 # move sp down by 2 word
sw $s0, 4($sp) # first word is the n in caller
sw $ra, 0($sp) # second word is the return addr of this callee
move $s0, $a0
subi $a0, $s0, 1
jal hanoi
sll $v0, $v0, 1 # hanoi(n - 1) * 2
ori $v0, $v0, 1 # hanoi(n - 1) * 2 + 1
lw $s0, 4($sp) # reverse s0
lw $ra, 0($sp) # reverse ra
addi $sp, $sp, 8
jr $ra

BIN
1/homework/exp2/a.in Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,206 @@
.data
compare_count: .word 0
num_N: .word 0
input_file_name: .asciiz "a.in"
.align 2
output_file_name: .asciiz "a.out"
.align 2
space_string: .asciiz " "
.align 2
newline_string: .asciiz "\r\n"
.align 2
num_buff: .space 4096
.align 2
.text
main:
la $a0, input_file_name
li $a1, 0
li $a2, 0
li $v0, 13
syscall
move $a0, $v0 # start to read in N
la $a1, num_N
li $a2, 4
li $v0, 14
syscall
la $t0, num_N # read N * 4 bytes into num_buff
lw $a2, 0($t0) # read in num_N
sll $a2, $a2, 2 # n * 4 is the bytes to read
la $a1, num_buff
li $v0, 14
syscall # read in file
li $v0, 16
syscall # close file
# jal print_num_in_buff
jal insertion_sort
# jal print_num_in_buff
la $a0, output_file_name
li $a1, 1
li $a2, 0
li $v0, 13
syscall
move $a0, $v0
la $a1, compare_count
li $a2, 4
li $v0, 15
syscall
la $a1, num_buff
la $a2, num_N
lw $a2, 0($a2)
sll $a2, $a2, 2
li $v0, 15
syscall
li $a0, 0
li $v0, 17
syscall # exit
insertion_sort:
subi $sp, $sp, 4
sw $ra, 0($sp)
la $t0, num_N
lw $s0, 0($t0) # n in s0
li $s1, 1 # i in s1
item_loop:
bge $s1, $s0, done_item_loop # if i >= n, done loop
li $a0, 0
subi $a1, $s1, 1
move $a2, $s1
jal binary_search
move $a0, $v0
move $a1, $s1
jal insert
addi $s1, $s1, 1 # i ++
j item_loop
done_item_loop:
lw $ra, 0($sp)
addi $sp, $sp, 8
jr $ra
binary_search: # a0: left, a1: right, a2: i
subi $sp, $sp, 20
sw $s0, 16($sp)
sw $s1, 12($sp)
sw $s2, 8($sp)
sw $s3, 4($sp)
sw $ra, 0($sp)
ble $a0, $a1, in_boundary_binary_search # left <= right, in normal position
move $v0, $a0 # now in boundary condition
j done_binary_search
in_boundary_binary_search:
move $s0, $a0 # in normal situation
move $s1, $a1
move $s2, $a2
add $s3, $s0, $s1 # s3 = mid = (left + right) >> 1
srl $s3, $s3, 1
jal add_compare_count
la $t0, num_buff
sll $t1, $s3, 2
add $t1, $t1, $t0
lw $t1, 0($t1) # t1 = v[mid]
sll $t2, $s2, 2
add $t2, $t2, $t0
lw $t2, 0($t2) # t2 = v[n]
ble $t1, $t2, binary_search_right # v[mid] <= v[n], jump to 'else'
binary_search_left:
subi $a1, $s3, 1
jal binary_search
j done_binary_search
binary_search_right:
addi $a0, $s3, 1
jal binary_search
done_binary_search:
lw $s0, 16($sp)
lw $s1, 12($sp)
lw $s2, 8($sp)
lw $s3, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 20
jr $ra
insert: # $a0: int k, $a1: int n
subi $sp, $sp, 12
sw $s0, 8($sp)
sw $s1, 4($sp)
sw $ra, 0($sp)
la $s0, num_buff # s0 = &v[0]
sll $t0, $a1, 2
add $s2, $s0, $t0
lw $s2, 0($s2) # s2 = tmp = 'pivot' = v[n]
subi $s1, $a1, 1 # s1 = i = n - 1
insert_loop:
blt $s1, $a0, done_insert_loop # i < k, done loop
sll $t0, $s1, 2
add $t0, $s0, $t0 # t0 = &v[i]
lw $t1, 0($t0)
sw $t1, 4($t0)
subi $s1, $s1, 1 # i--
j insert_loop
done_insert_loop:
sll $t0, $a0, 2
add $t0, $s0, $t0
sw $s2, 0($t0) # t0 = &v[k]
lw $s0, 8($sp)
lw $s1, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 12
jr $ra
add_compare_count:
la $t0, compare_count
lw $t1, 0($t0)
addi $t1, $t1, 1
sw $t1, 0($t0)
jr $ra
print_num_in_buff:
la $t0, num_N
la $t2, num_buff
lw $t0, 0($t0)
li $t1, 0
print_loop:
bge $t1, $t0, done_print_loop
sll $a0, $t1, 2
add $a0, $t2, $a0
lw $a0, 0($a0)
li $v0, 1
syscall
la $a0, space_string
li $v0, 4
syscall
addi $t1, $t1, 1
j print_loop
done_print_loop:
la $a0, newline_string
li $v0, 4
syscall
jr $ra

View File

@@ -0,0 +1,189 @@
.data
compare_count: .word 0
num_N: .word 0
input_file_name: .asciiz "a.in"
.align 2
output_file_name: .asciiz "a.out"
.align 2
space_string: .asciiz " "
.align 2
newline_string: .asciiz "\r\n"
.align 2
num_buff: .space 4096
.align 2
.text
main:
la $a0, input_file_name
li $a1, 0
li $a2, 0
li $v0, 13
syscall
move $a0, $v0 # start to read in N
la $a1, num_N
li $a2, 4
li $v0, 14
syscall
la $t0, num_N # read N * 4 bytes into num_buff
lw $a2, 0($t0) # read in num_N
sll $a2, $a2, 2 # n * 4 is the bytes to read
la $a1, num_buff
li $v0, 14
syscall # read in file
li $v0, 16
syscall # close file
jal insertion_sort
la $a0, output_file_name
li $a1, 1
li $a2, 0
li $v0, 13
syscall
move $a0, $v0
la $a1, compare_count
li $a2, 4
li $v0, 15
syscall
la $a1, num_buff
la $a2, num_N
lw $a2, 0($a2)
sll $a2, $a2, 2
li $v0, 15
syscall
li $a0, 0
li $v0, 17
syscall # exit
insertion_sort:
subi $sp, $sp, 4
sw $ra, 0($sp)
la $t0, num_N
lw $s0, 0($t0) # n in s0
li $s1, 1 # i in s1
item_loop:
bge $s1, $s0, done_item_loop # if i >= n, done loop
move $a0, $s1
jal search
move $a0, $v0
move $a1, $s1
jal insert
addi $s1, $s1, 1 # i ++
j item_loop
done_item_loop:
lw $ra, 0($sp)
addi $sp, $sp, 8
jr $ra
search: # $a0: int n
subi $sp, $sp, 12
sw $s0, 8($sp)
sw $s1, 4($sp)
sw $ra, 0($sp)
la $s0, num_buff
sll $t0, $a0, 2
add $s2, $s0, $t0
lw $s2, 0($s2) # s2 = tmp = v[n]
subi $s1, $a0, 1 # i = n - 1
search_loop:
bltz $s1, done_search_loop # i < 0, done loop
jal add_compare_count
sll $t0, $s1, 2
add $t0, $s0, $t0
lw $t0, 0($t0) # t0 = v[i]
ble $t0, $s2, done_search_loop # if v[i] <= tmp, break
subi $s1, $s1, 1 # i--
j search_loop
done_search_loop:
addi $v0, $s1, 1 # return i + 1
lw $s0, 8($sp)
lw $s1, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 12
jr $ra
insert: # $a0: int k, $a1: int n
subi $sp, $sp, 12
sw $s0, 8($sp)
sw $s1, 4($sp)
sw $ra, 0($sp)
la $s0, num_buff # s0 = &v[0]
sll $t0, $a1, 2
add $s2, $s0, $t0
lw $s2, 0($s2) # s2 = tmp = 'pivot' = v[n]
subi $s1, $a1, 1 # s1 = i = n - 1
insert_loop:
blt $s1, $a0, done_insert_loop # i < k, done loop
sll $t0, $s1, 2
add $t0, $s0, $t0 # t0 = &v[i]
lw $t1, 0($t0)
sw $t1, 4($t0)
subi $s1, $s1, 1 # i--
j insert_loop
done_insert_loop:
sll $t0, $a0, 2
add $t0, $s0, $t0
sw $s2, 0($t0) # t0 = &v[k]
lw $s0, 8($sp)
lw $s1, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 12
jr $ra
add_compare_count:
la $t0, compare_count
lw $t1, 0($t0)
addi $t1, $t1, 1
sw $t1, 0($t0)
jr $ra
print_num_in_buff:
la $t0, num_N
la $t2, num_buff
lw $t0, 0($t0)
li $t1, 0
print_loop:
bge $t1, $t0, done_print_loop
sll $a0, $t1, 2
add $a0, $t2, $a0
lw $a0, 0($a0)
li $v0, 1
syscall
la $a0, space_string
li $v0, 4
syscall
addi $t1, $t1, 1
j print_loop
done_print_loop:
la $a0, newline_string
li $v0, 4
syscall
jr $ra

View File

@@ -0,0 +1,253 @@
.data
compare_count: .word 0
num_N: .word 0
input_file_name: .asciiz "a.in"
.align 2
output_file_name: .asciiz "a.out"
.align 2
space_string: .asciiz " "
.align 2
newline_string: .asciiz "\r\n"
.align 2
num_buff: .space 4096
.align 2
.text
main:
la $a0, input_file_name
li $a1, 0
li $a2, 0
li $v0, 13
syscall
move $a0, $v0 # start to read in N
la $a1, num_N
li $a2, 4
li $v0, 14
syscall
la $t0, num_N # read N * 4 bytes into num_buff
lw $a2, 0($t0) # read in num_N
sll $a2, $a2, 2 # n * 4 is the bytes to read
la $a1, num_buff
li $v0, 14
syscall # read in file
li $v0, 16
syscall # close file
la $t0, num_N
lw $s0, 0($t0) # s0 = N
li $a0, 8
li $v0, 9
syscall
move $s2, $v0 # headptr in s2
move $s3, $s2 # curnodeptr = headptr
li $s1, 0 # s1 = index
la $t0, num_buff
create_linked_list:
bge $s1, $s0, done_create_linked_list
li $v0, 9
syscall # new int[2]
sw $v0, 4($s3) # curnodeptr[1] = new int[2]
move $s3, $v0 # curnodeptr = curnodeptr[1]
sll $t1, $s1, 2 # curnodeptr[0] = num_buffer[index]
add $t1, $t0, $t1
lw $t1, 0($t1)
sw $t1, 0($s3)
sw $zero, 4($s3) # curnodeptr[1] = NULL
addi $s1, $s1, 1
j create_linked_list
done_create_linked_list:
# lw $a0, 4($s2) #a0 = headnodeptr[1]
# jal print_num
lw $a0, 4($s2) #a0 = headnodeptr[1]
jal merge_sort
sw $v0, 4($s2)
move $s1, $s2 # curptr = headptr
# lw $a0, 4($s2) #a0 = headnodeptr[1]
# jal print_num
la $a0, output_file_name
li $a1, 1
li $a2, 0
li $v0, 13
syscall
move $a0, $v0
la $a1, compare_count
li $a2, 4
li $v0, 15
syscall
write_linked_list:
lw $s1, 4($s1) # curptr = curptr[1]
beq $s1, $zero, done_write_linked_list
move $a1, $s1
li $v0, 15
syscall
j write_linked_list
done_write_linked_list:
li $v0, 16
syscall
li $a0, 0
li $v0, 17
syscall # exit
merge_sort: # a0: headnodeptr
subi $sp, $sp, 20
sw $s0, 16($sp)
sw $s1, 12($sp)
sw $s2, 8($sp)
sw $s3, 4($sp)
sw $ra, 0($sp)
lw $t0, 4($a0) # t0 = headnodeptr[1]
bne $t0, $zero, valid_head # if headnodeptr[1] != NULL, valid head
move $v0, $a0 # no valid head
j done_merge_sort
valid_head:
move $s1, $a0 # stride 1 pointer
move $s2, $a0 # stride 2 pointer
find_mid:
lw $s2, 4($s2) # s2 = s2[1]
beq $s2, $zero, done_find_mid # s2 == NULL, break
lw $s2, 4($s2) # s2 = s2[1]
beq $s2, $zero, done_find_mid # s2 == NULL, break
lw $s1, 4($s1)
j find_mid
done_find_mid:
lw $s2, 4($s1) # now s2 is the headnodeptr of the right part
sw $zero, 4($s1)
jal merge_sort # no need to set a0 to head, it already is
move $s1, $v0 # save the result of first merge_sort to s1
move $a0, $s2
jal merge_sort # merge_sort for right part
# move $a0, $s1
# jal print_num
# move $a0, $v0
# jal print_num
move $a0, $s1
move $a1, $v0
jal merge_list
done_merge_sort:
lw $s0, 16($sp)
lw $s1, 12($sp)
lw $s2, 8($sp)
lw $s3, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 20
jr $ra
merge_list: # a0: l_head, a1: r_head
subi $sp, $sp, 28
sw $s0, 24($sp)
sw $s1, 20($sp)
sw $s2, 16($sp)
sw $s3, 12($sp)
sw $s4, 8($sp)
sw $s5, 4($sp)
sw $ra, 0($sp)
move $s0, $a0 # lheadptr
move $s1, $a1 # s1 = rheadptr
li $a0, 8
li $v0, 9
syscall # create dummy node
sw $s0, 4($v0) # headnodeptr[1] = lheadptr
move $s0, $v0 # p_left = headnodeptr; p_right = rightptr, no change.
move $s7, $v0 # head
do_merge_list: # outer while
find_left_merge_pos:
lw $s2, 4($s0) #p_left[1]
beq $s2, $zero, direct_add_right_part
jal add_compare_count
lw $s2, 0($s2) # (p_left[1])[0]
lw $t0, 0($s1) # p_right[0]
bgt $s2, $t0, no_direct_add_right_part
lw $s0, 4($s0)
j find_left_merge_pos
direct_add_right_part:
sw $s1, 4($s0)
j done_do_merge_list
no_direct_add_right_part:
move $s2, $s1 # p_right_temp
lw $s5, 4($s0)
lw $s5, 0($s5) # (p_left[1])[0]
find_right_merge_pos:
lw $s3, 4($s2) # p_right_temp[1]
beq $s3, $zero, done_find_right_merge_pos
jal add_compare_count
lw $s4, 0($s3) # (p_right_temp[1])[0]
bgt $s4, $s5, done_find_right_merge_pos
move $s2, $s3 # p_right_temp = p_right_temp[1]
j find_right_merge_pos
done_find_right_merge_pos:
move $s4, $s3 # temp_right_pointer_next
lw $t0, 4($s0) # p_left[1]
sw $t0, 4($s2) # p_right_temp[1] = p_left[1]
sw $s1, 4($s0) # p_left[1] = p_right
move $s0, $s2
move $s1, $s4
beq $s1, $zero, done_do_merge_list
j do_merge_list
done_do_merge_list:
lw $v0, 4($s7)
done_merge_list:
lw $s0, 24($sp)
lw $s1, 20($sp)
lw $s2, 16($sp)
lw $s3, 12($sp)
lw $s4, 8($sp)
lw $s5, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 28
jr $ra
add_compare_count:
la $t0, compare_count
lw $t1, 0($t0)
addi $t1, $t1, 1
sw $t1, 0($t0)
jr $ra
print_num: #a0: headptr
subi $sp, $sp, 8
sw $t0, 4($sp)
sw $v0, 0($sp)
move $t0, $a0
print_loop:
lw $a0, 0($t0)
li $v0, 1
syscall
la $a0, space_string
li $v0, 4
syscall
lw $t0, 4($t0)
beq $t0, $zero, done_print_num
j print_loop
done_print_num:
la $a0, newline_string
li $v0, 4
syscall
lw $t0, 4($sp)
lw $v0, 0($sp)
addi $sp, $sp, 8
jr $ra

85
1/homework/report.tex Normal file
View File

@@ -0,0 +1,85 @@
\documentclass[11pt, a4paper]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage[inline]{enumitem}
\usepackage{amsmath}
\usepackage{float}
\usepackage{listings}
\usepackage{fontspec}
\usepackage{xcolor}
% \newfontfamily\codefont[Ligatures=ResetAll]{Fira Code}[Contextuals={Alternate}]
\newfontfamily\codefont{Cascadia Code}
\lstset{
basicstyle = \small\codefont,
% ---
tabsize = 4,
showstringspaces = false,
numbers = left,
numberstyle = \codefont,
% ---
breaklines = true,
captionpos = t,
% ---
frame = l,
flexiblecolumns,
columns = fixed,
}
\lstdefinestyle{asmstyle}{
% basicstyle = \small\codefont,
keywordstyle=\bfseries\color{green!40!black},
commentstyle=\color{purple!40!black},
identifierstyle=\color{blue!80!white},
}
\title{\textbf{Report for First Assembly Homework}}
\author{2022010639 高艺轩}
\date{}
\begin{document}
\maketitle
\section{Basic Exercises}
\subsection{System Call}
The code is essentially a set of system calls. Set the values in \lstinline{$a0, $a1, $a2} as the arguments to pass to the operation system, and use \lstinline{$v0} to change the exact systemcall.
These systemcalls first open file as read only, then read the contents into the memory; close the file, then open another file in write only mode and write the content just read from the other file.
The last two systemcalls are reading from \lstinline{stdin} and output to \lstinline{stdout}, respectively.
\subsection{Loop and Branch}
The \lstinline{for} loop and \lstinline{if} clause in high level programming language is written in a way that we write the action to do when the expression is satisfied at the top, and then write the other part after that. However, to achieve similar structure in assembly code, we have to compose the logic in the way of ``If the expression is NOT met, then jump further away so the instructions right behind this jump instruction is NOT executed'', and by this way, when the expression is met, \lstinline{pc} won't be altered and the code below will be executed.
The program first read in \lstinline{i} and \lstinline{j} from \lstinline{stdin}, then use a \lstinline{bgez} to decided whether \lstinline{j = -j} needed to be executed. Then, set a register as temp, and count it up to add 1 to \lstinline{i} every time until temp is greater than or equal to (\lstinline{bge}) \lstinline{j}. Lastly, print out the result and set the return value.
\subsection{Array and Pointer}
First, read in the total number \lstinline{n} of the upcoming numbers; Then, request \lstinline{n << 2} bytes of space to store the numbers. Use \lstinline{$t0} as the counter, and \lstinline{$t1} as the pointer, write the number read into memory. Doing the reverse is similar to this. Every iteration adds \lstinline{$t1} by 4 and subtracts \lstinline{$t2} by 4 so that \lstinline{a[i]} and \lstinline{a[n - i - 1]} can be accessed. At last, cycle through the number once more to output the results.
\subsection{Function Call}
Function call is actually very similar to what it is in higher level language. The only difference is that inside a procedure call, first move \lstinline{$sp} by some distance and store all the registers that are required to be preserved but also used by this procedure call, including \lstinline{$ra}. Then write the procedure as if it is a normal program, the arguments of the call is stored in \lstinline{$a0, $a1, $a2} and should be copied to saved registers if needed later. At the end of the procedure, save the return value to \lstinline{$v0}, restore all the saved register value from stack and restore \lstinline{$sp} then call \lstinline{jr $ra} to return.
\section{Practical Application}
\subsection{Direct Insertion Sort}
In \lstinline{insertion_sort}, \lstinline{$s0} is the \lstinline{n}, \lstinline{$s1} is the \lstinline{i} in \lstinline{for} loop. For every element in the list, the procedure uses \lstinline{search} to find its correct position, and use insert to insert it into that position.
In \lstinline{search}, \lstinline{$s0} is \lstinline{&v[0]} and \lstinline{$s2} is \lstinline{v[n]}, \lstinline{$s1} is \lstinline{i} in the \lstinline{search_loop}. The procedure finds the first number that is smaller than the target number, and return the address of one after this smaller number.
In \lstinline{insert}, \lstinline{$s0 = &v[0]}, \lstinline{$s2 = v[n]}, \lstinline{$s1 = i}, string from \lstinline{n - 1}. The procedure moves everything after the target's correct position one slot backward, and then insert the target into its correct position.
In \lstinline{add_compare_count}, the procedure loads the stored compare count, add 1 to it, and then write it back to memory.
\lstinline{print_num_in_buff} is a procedure used for debugging. It prints out all the number in the number buffer, seperated by space and ended by \lstinline{\r\n}.
\subsection{Binary Insertion Sort}
The overall design and structure of the program is same as the `Direct Insertion Sort'. The only difference is that the \lstinline{search} procedure now uses binary search to search for the correct position of the target number.
In the new \lstinline{binary_search} procedure, \lstinline{$s1 = left}, \lstinline{$s2 = right}, \lstinline{$s3 = mid}, and \lstinline{$t0 = &v[0]}, \lstinline{$t1 = v[mid]}, \lstinline{$t2 = v[n] = target_number}. Every time the procedure finds the number in the middle of left and right and compare it with the target number; if the middle number is larger, then further search for left part; if the middle number is smaller, then further search for right part. Do this recursively until the left bound is larger than right bound, which means the left bound is the position to insert this target number.
\subsection{Merge Sort}
The C++ code uses linked list, and thus the \lstinline{main} part of the code have to create the linked list after reading the file into the memory. For every number, allocate a new node on heap, then save the pointer and content. Then it calls \lstinline{merge_sort} and save the sort result into file.
In \lstinline{merge_sort}, \lstinline{$s1} is the stride 1 pointer and \lstinline{$s2} is the stride 2 pointer that goes 2 steps every 1 step the stride 1 pointer tooks. When stride 2 pointer reaches the end of the list, stride 1 pointer is pointing at the middle of the list. Then it breaks the list at the middle, and calls \lstinline{merge_sort} on both parts. Then, use \lstinline{merge_list} to merge back the two parts into a ordered list.
In \lstinline{merge_list}, \lstinline{$s0} is the \lstinline{p_left}, \lstinline{$s1} is the \lstinline{p_right}, and \lstinline{$s7} is the \lstinline{head}. \lstinline{$s2, $s3, $s4, $s5} are used according to the needs, they are typically \lstinline{p_left[1]}, or \lstinline{(p_left[1])[0]}, or \lstinline{p_right_temp}, which are labeled in comments. In essence, the proceture takes two ordered list and reconnect them to combine them into one ordered list.
\end{document}