Ví dụ:
int a = 7; int b = 5; int c;
- c = a + b;
Ý tưởng: đưa giá trị từng biến a, b, c ở các ô nhớ vào từng thanh ghi trong tập thanh ghi
- (của CPU), tiến hành tính toán và đưa vào thanh ghi, sau đó đưa kết quả vào các ô nhớ. Chương trình: .data addrA: addrB: addrC: .text main: lui lw lui lw add lui sw 3.1.-2. Làm việc với mảng
Mảng với n phần tử là một chuỗi n phần tử liên tiếp nhau trong bộ nhớ. Thao tác với mảng trong MIPS là thao tác trực tiếp với byte/word trong bộ nhớ.
+ Để cấp phát chuỗi word hoặc byte trong bộ nhớ, có giá trị khởi tạo sử dụng “.word” hoặc “.byte” trong “.data”.
+ Để cấp phát chuỗi byte không có giá trị khởi tạo trước, sử dụng “.space” trong “.data”
- Ví dụ:
-
-
clear1(int array[], int size) { int i;
for (i = 0; i < size; i++) array[i] = 0; }
Ý tưởng: $a0 là địa chỉ của array, $a1 là kích thước của array (size), lần lượt tìm địa chỉ của các phần tử mảng kế tiếp (bằng cách cộng lần lượt 0, 4, 8, 12, ... vào địa chỉ mảng $a0) và lưu giá trị 0 tại đó, lặp lại đến khi biến i ($t0) không nhỏ hơn kích thước mảng ($a1) Chương trình: .text add $8, $0, $0 loop: sll $9, $8, 0x00000002 add $10, $4, $9 sw $0, 0x00000000($10) addi $8, $8, 0x00000001 slt $11, $8, $5 bne $11, $0, loop 3.1.-3. Làm việc với con trỏ
Con trỏ là một biến lưu địa chỉ của một biến khác. Thao tác với con trỏ trong MIPS là - thao tác trực tiếp với địa chỉ
bộ nhớ. Ví dụ:
-
clear2(int *array, int size) { int *p;
for (p = &array[0]; p < &array[size]; p++)
*p = 0;
Ýtưởng: $a0 là địa chỉ của array, $a1 là kích thước của array (size), con trỏ $t0 là địa chỉ phần tử đầu tiên, $t2 là địa chỉ của phần tử cuối cùng (qua tính toán), sau đó lặp lại việc thay đổi giá trị tại con trỏ ($t0=0) và dời con trỏ sang địa chỉ của phần tử kế tiếp ($t0+=4) cho đến khi con trỏ $t0 không nhỏ hơn $t2 (địa chỉ phần tử cuối).
24
- Chương trình: .text add $8, $0, $4 sll $9, $5, 0x00000002 add $10,$4,$9 loop: sw $0, 0x00000000($8) addi $8, $8, 0x00000004 slt $11, $8, $10 bne $11, $0, loop 3.1.-4. Lý do nên sử dụng con trỏ
Tốc độ nhanh hơn (vì số câu lệnh trong vòng lặp (LOOP) khi sử dụng con trỏ ít hơn khi
- sử dụng mảng).
Đúng với bản chất của việc truy xuất bộ nhớ.
3.2. Thực hành
3.2.1. Thao tác với mảng
Cho 3 mảng với cấp phát dữ liệu trong bộ nhớ như sau:
.data array1: .word size1: .word 10 array2: .byte size2: .word 16 array3: .space size3: .word 8
Mảng array1 có 10 words, kích thước được lưu trong size1; Mảng array2 có 16 bytes, kích thước được lưu trong size2; Mảng array3 có 8 bytes, kích thước được lưu trong size3. Viết code phần “.text” thực hiện riêng từng phần việc:
In ra cửa sổ I/O của MARS tất cả các phần tử của mảng array1 và array2.
Gán các giá trị cho mảng array3 sao cho:
array3[i] = array2[i] + array2[size2 – 1 – i]
Người sử dụng nhập vào mảng thứ mấy và chỉ số phần tử cần lấy trong mảng đó, chương trình xuất ra phần tử tương ứng25.
Trả lời:
Yêucầu 1: xuất các phần tử của mảng array1 và array2 ra cửa sổ I/O:
-
Ý tưởng: truy xuất phần tử của mảng theo chỉ số mảng, tức nghĩa là dựa vào chỉ số mảng để tính toán địa chỉ của phần tử đang xét (mảng array1 với mỗi phần tử kiểu word có độ lớn 4 bytes, mảng array2 với mỗi phần tử có độ lớn 1 byte), lặp lại các
-
công đoạn tính toán đến khi chỉ số mảng không nhỏ hơn kích thước mảng. Ta có sơ đồ thuật toán như sau:
Bắt đầu $t0 = 0 $t1 = size1 $a1 = &array1 $a0 = &array1[$t0] $v0 = 1, Syscall Xuất phần tử mảng $t0 = $t0 + 1 Đ $t0 < $t1 S
Hình 3.1 – Sơ đồ thuật toán xuất các phần tử của mảng array1 và array2
Yêu cầu 2: thực hiện gán các giá trị lần lượt cho từng phần tử của mảng array3 theo biểu thức-array3[i] = array2[i] + array2[size2 – 1 – i]
Ý tưởng: truy xuất phần tử của mảng theo chỉ số mảng (tương tự như yêu cầu 1), tuy nhiên việc tính toán địa chỉ của26phần tử array2[size2 – 1 – i] có hơi khác so với
phần tử array2[i] ở chỗ ta phải tính ra địa chỉ của phần tử cuối cùng của mảng
- array2 trước.
Ta có sơ đồ thuật toán như sau:
Bắt đầu $t0 = 0 $t3 = size3 $a3 = &array3 $t2 = size2 – 1 $a2 = &array2 $s1 = &array3[$t0] $s2 = &array2[$t0] $s3 = &array2[size2 – 1 – $t0] $t4 = *($s2) $t5 = *($s3) $t6 = $t5 + $t4 *($s1) = $t6 $t0 = $t0 + 1 Đ $t0 < $t3 S Kết thúc
Hình 3.2 – Sơ đồ thuật toán thực hiện gán các giá trị cho các phần tử mảng array3 Yêu cầu 3: xuất ra phần tử tuỳ chọn tương ứng
27
- Ý tưởng: nếu số nguyên đầu tiên nhập vào là 1 thì truy xuất mảng array1, nếu là 2 thì truy xuất mảng array2; thực hiện việc truy xuất phần tử có chỉ số là số nguyên nhập vào thứ hai tương tự như cách tính ở 2 yêu cầu trên.
- Ta có sơ đồ thuật toán như sau: Bắt đầu $v0 = 5, Syscall Nhập số nguyên $s0 = $v0 $v0 = 5, Syscall Nhập số nguyên $s0 là 1 (array1) hoặc 2 (array2) $a0 = array1[$s1] $s1 = $v0 $s0 == 1 $s1 là chỉ số phần tử của mảng $a0 = array2[$s1] $v0 = 1, Syscall Xuất số nguyên Kết thúc
Chương trình:
3.2.2. Thao tác với con trỏ
Thực hiện lại nội dung “Thao tác với mảng” với con trỏ.
Trả-lời:
Ý tưởng: truy xuất phần tử bằng chỉ số mảng thì trong điều kiện dừng, biến chạy phải so sánh với kích thước mảng, còn khi thao tác với con trỏ thì biến con trỏ - phải so sánh với một biến con trỏ khác chứa địa chỉ của phần tử cuối cùng.
Sơ đồ giải thuật:
Bắt đầu $t0 = &array1[0] $t1 = &array1[size1 – 1] $a0 = *($t0) $v0 = 1, Syscall Xuất số nguyên $t0 = $t0 + 1 Đ S $t0 < $t1 $v0 = 5, Syscall Nhập số nguyên $v0 = 5, Syscall Nhập số nguyên $s0 = $v0 $s1 = $v0 $s0 == 1
$a0 = array1[$s1] $a0 = array2[$s1]
$v0 = 1, Syscall
29
Kết thúc
Hình 3.4 – Sơ đồ giải thuật bài toán thao tác với con trỏ
- Chương trình:
3.3. Bài tập3.3.1. Bài tập 1 3.3.1. Bài tập 1
a. Đề bài:
Nhập một mảng các số nguyên n phần tử (nhập vào số phần tử và giá trị của từng phần tử), xuất ra cửa sổ I/O của MARS theo từng yêu cầu sau:
Xuất ra giá trị lớn nhất và nhỏ nhất của mảng.
Tổng tất cả các phần tử của mảng.
Người sử dụng nhập vào chỉ số của một phần tử nào đó và giá trị của phần tử đó được in ra cửa sổ.
b. Sơ đồ giải thuật:
c. Chương trình:
3.3.2. Bài tập 2
a. Đề bài:
Nhập một mảng các số nguyên n phần tử (nhập vào số phần tử và giá trị của từng phần tử), xuất ra cửa sổ I/O của MARS theo từng yêu cầu sau:
Xuất ra giá trị lớn nhất và nhỏ nhất của mảng.
Tổng tất cả các phần tử của mảng.
Người sử dụng nhập vào chỉ số của một phần tử nào đó và giá trị của phần tử đó được in ra cửa sổ.
b. Sơ đồ giải thuật:
c. Chương trình:
30
CHƯƠNG 4. THỦ TỤC (HÀM CON) 4.1. Lí thuyết 4.1.1.- Thủ tục Quy trình thực hiện: Lệnh A Thực thi thủ tục Quay về chương trình chính Lệnh C
Hình 4.1 – Quy trình thực hiện lời gọi thủ tục
4.1.2. Thủ tục với MIPS
Bước 1. Chuẩn bị đối số. Bước 2. Lưu trạng thái. Bước 3. Nhảy tới thủ tục. Bước 4. Thực thi thủ tục. Bước 5. Chuẩn bị kết quả.
Bước 6. Quay về chương trình chính (tại lệnh kế tiếp). Quy ước:
+ Thanh ghi đối số: $a0 - $a3
+ Thanh ghi kết quả: $v0, $v1
+ Thanh ghi tạm: $t0 - $t9
+ Thanh ghi lưu trữ: $s0 - $s7
+ Thanh ghi địa chỉ trả về: $ra
+ Thanh ghi con trỏ ngăn xếp: $sp
Lưu ý: phải bảo toàn dữ liệu trong ngăn xếp trước khi gọi thủ tục
…
31
4.1.3. VÍ DỤ
void main ( ) { int s = 0;
s = sum(15,12); }
int sum(int a, int b) { int t = a + b; return t; } add $s0, $0, $0 addi $a0, $0, 15 add $a1, $0, 12 jal sumPro add $s0, $0, $v0 j exit sumPro:
add $v0, $a0, $a1 jr $ra
exit:
4.1.4. LỒNG THỦ TỤC
Bước 1. Chuẩn bị đối số.
Bước 2. Lưu trạng thái. Bước 3. Nhảy tới thủ tục. Bước 4. Thực thi thủ tục. Bước 5. Chuẩn bị kết quả.
Bước 6. Quay về chương trình chính (tại lệnh kế tiếp).
Lưu ý: Trước khi gọi thủ tục khác phải lưu lại thanh ghi $ra rồi mới nhảy tới thủ tục mới (Nếu muốn chắc chắn có thể lưu lại thanh ghi $sp).
32
4.2. Thực hành
4.2.1. IN RA CỬA SỔ I/O GIÁ TRỊ CỦA SỐ INT NHẬP VÀO CỘNG THÊM 1
abc
4.2.2. TÍNH GIÁ TRỊ BIỂU THỨC (A+B) – (C+D) VÀ (A-B) + (C-D)
abc
4.2.3. TÍNH GIÁ TRỊ BIỂU THỨC (A+B) – (C+D) VÀ (E-F)
abc 4.3. Bài tập 4.3.1. TÍNH GIAI THỪA abc 33 download by : skknchat@gmail.com
TÀI LIỆU THAM KHẢO
[1] Làm quen cách sử dụng Vim với Vimtutor, http://notes.viphat.work/vimtutor
34