Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

26
1. Gii thiu PCSPim PCSpim là chương trình chy và mô phng chương trình hp ngdành cho MIPS. Sau khi cài đặt PCSpim và chy chương trình (Start -> All Programs -> PCSpim.exe), ca schương trình PCSpim hin lên như hình 1. Hình 1: Ca schương trình PCSpim Ca shin thchia làm 4 phn: Phn trên cùng hin thni dung ca 32 thanh ghi ca CPU và FPU. Ni dung stđộng cp nht khi chương trình hp ngchy. Phn dưới kế tiếp hin thmã ca chương trình dng hp ng, dng mã máy (shex ct th2 ttrái qua), và địa chtương ng ca mi lnh (ct đầu tiên bên trái). Phn dưới kế tiếp hin thdliu khai báo trong chương trình hp ng(ví d: mng hay chui) và dliu trong vùng ngăn xếp khi chương trình hp ngđược thc thi. Phn dưới cùng hin thcác thông tin phca SPIM, thông tin vli nếu có. Chương trình hp ngmun chy được phi được load trước. Đế load chương trình hp ng(dng mt file có đuôi mrng là *.asm hay *.s), thc hin thao tác File menu -> Open -> chn file cha chương trình cn load. Để to file *.asm, chúng ta có thdùng các chương trình son tho thô như Notepad, Notepad++, EditPlus…

Transcript of Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

Page 1: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

1. Giới thiệu PCSPim

PCSpim là chương trình chạy và mô phỏng chương trình hợp ngữ dành cho MIPS. Sau khi cài đặt PCSpim và chạy chương trình (Start -> All Programs -> PCSpim.exe), cửa sổ chương trình PCSpim hiện lên như hình 1.

Hình 1: Cửa sổ chương trình PCSpim

Cửa sổ hiển thị chia làm 4 phần:

• Phần trên cùng hiển thị nội dung của 32 thanh ghi của CPU và FPU. Nội dung sẽ tự động cập nhật khi chương trình hợp ngữ chạy.

• Phần dưới kế tiếp hiển thị mã của chương trình ở dạng hợp ngữ, dạng mã máy (số hex cột thứ 2 từ trái qua), và địa chỉ tương ứng của mỗi lệnh (cột đầu tiên bên trái).

• Phần dưới kế tiếp hiển thị dữ liệu khai báo trong chương trình hợp ngữ (ví dụ: mảng hay chuỗi) và dữ liệu trong vùng ngăn xếp khi chương trình hợp ngữ được thực thi.

• Phần dưới cùng hiển thị các thông tin phụ của SPIM, thông tin về lỗi nếu có. Chương trình hợp ngữ muốn chạy được phải được load trước. Đế load chương trình hợp

ngữ (ở dạng một file có đuôi mở rộng là *.asm hay *.s), thực hiện thao tác File menu -> Open -> chọn file chứa chương trình cần load. Để tạo file *.asm, chúng ta có thể dùng các chương trình soạn thảo thô như Notepad, Notepad++, EditPlus…

Page 2: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

Hình 2. Load file chứa chương trình nguồn.

Sau khi chương trình hợp ngữ đã được load, chúng ta có thể thực hiện chạy chương trình và quan sát sự thay đối giá trị các thanh ghi, các ô nhớ, vị trí và lệnh đang được thực thi … Các tác vụ chạy chương trình ở trong Simulator menu.

Các bước để chạy và quan sát quá trình chạy của chương trình hợp ngữ trên PCSpim:

• Chọn Simulator -> Breakpoints… (hoặc nhấn Ctrl+B). Cửa sổ hiện ra điền vào textbox Address giá trị 0x00400000, chọn Add.

• Chọn Simulator -> Go (hoặc nhấn F5). Điền giá trị 0x00400000 vào texbox Starting Address, chọn OK. Giá trị của thanh ghi PC lúc này là 0x00400000.

• Chọn Simulator -> Single Step (hoặc nhấn F10) để chạy từng dòng lện trong chương trình. Chúng ta có thể quan sát kết quả thực hiện thông qua giá trị của các thanh ghi, các ô nhớ liên quan.

Page 3: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

Cách khác để chạy chương trình nguồn: Simularor -> SetValue…, cửa sổ hiện ra, điền vào textbox Register Name giá trị PC, điền vào textbox Value giá trị 0x00400000. Sau đó nhấn F10 để chạy từng bước hay F5 để chạy cho đến khi gặp breakpoints.

2. Các kiến thức cơ sở 2.1 Đổi qua lại giữ số thập lục phân (hexadecimal) và số nhị phân (binary)

Số thập lục phân được tạo thành từ 16 ký số: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. Số nhị phân tạo thành từ 2 ký số: 0, 1. Một ký số thập lục phân tương ứng với số nhị phân gồm 4 ký số theo bảng sau:

Ví dụ: Số thập lục phân 0xeca86420 chuyển sang số nhị phân:

Số nhị phân 1 0011 0101 0111 1001 1011 1101 1111 chuyển sang số thập lục phân:

2.2 Tổ chức bộ nhớ

Bộ nhớ là một mảng 232 ô nhớ 8-bit, bắt đầu từ địa chỉ 0x000000 đến địa chỉ 0xFFFFFFFF. Người dùng chỉ có thể sử dụng vùng nhớ từ 0x00400000 đến 0x7FFFFFFF. Vùng nhớ người dùng chia làm 3 phần: vùng chứa mã (text segment), vùng chứa dữ liệu (data segment)

Page 4: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

và vùng nhớ stack (stack segment). Bộ xử lý tương tác với bộ nhớ thông qua việc di chuyển dữ liệu giữa các ô nhớ và các thanh ghi. Có hai thao tác để thực hiện việc di chuyển dữ liệu giữa bộ nhớ và thanh ghi: load và store. Dữ liệu di chuyển được tổ chức thành nhóm một, hai hay bốn byte liên tục nhau theo chiều tăng địa chỉ ô nhớ.

• load: nhóm byte liên tục nhau theo chiều tăng địa chỉ ô nhớ bắt đầu từ địa chỉ được chỉ định được copy vào thanh ghi.

• store: nhóm dữ liệu 1, 2 byte thấp của thanh ghi hay cả 4 byte của thanh ghi được copy vào bộ nhớ từ địa chỉ được chỉ định.

2.3 Tổ chức thanh ghi

MIPS có tấc cả 32 thanh ghi 32-bit có thê sử dụng trong ngôn ngữ assembly được liệt kê trong bảng sau:

Bộ xử lý MIPS có bộ tính toán số học/luận lý (ALU) bên trong thực hiện các phép toán số học và luận lý trên số nguyên 32-bit. Phép toán thực hiện bởi ALU gồm hai toán hạng. Một toán hạng là số nguyên chứa trong thanh ghi, toán hạng còn lại có thể chứa trên thanh ghi hay là một phần của lệnh thực hiện phép toán (hằng số). Kết quả của phép toán luôn đặt vào thanh ghi.

Page 5: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

3. Tập lệnh của MIPS Lệnh Cú pháp Định dạng lệnh Ý nghĩa

Cộng số bù 2 add rd, rs, rt

rd <-- rs+rt ;

Cộng không dấu addu rd, rs, rt

rd <-- rs+rt ;

Cộng với hằng số 16 bit bù 2

addi rd, rs, const

rd rs+const ;

Cộng với hằng số 16 bit không dấu

addiu rd, rs, const

rd rs+const ;

AND từng bit and rd, rs, rt

rd bitwise AND of rs with rt

AND từng bit với hằng số 16 bit

andi rd, rs, const

rd bitwise AND of rs with const

Nhảy nếu bằng beq rs, rt, addr

nhảy đến addr nếu rs == rt. Cần phải thêm delay theo sau (nop)

Nhảy nếu lớn hơn hay bằng 0

bgez rs, addr

nhảy đến addr nếu số bù 2 trong rs >= 0. Cần thêm delay

Nhảy nếu nhỏ hơn 0

bltz rs, addr

nhảy đến addr nếu số bù 2 trong rs < 0. Cần thêm delay

Nhảy nếu khác bne rs, rt, addr

nhảy đến addr nếu rs != rt. Cần thêm delay

Chia hai số bù 2 div rs, rt

lo rs div rt; hi rs mod rt hai số rs và rt ở dạng bù 2

Chia hai số không dấu

divu rs, rt

lo rs div rt; hi rs mod rt hai số rs và rt ở dạng không dấu

Nhảy không điều kiện

j target

delay sau một chu kỳ máy: PC địa chỉ của target

Nhảy không điều kiện và link

jal target

gọi hàm target, $ra = PC +4 PC địa chỉ của target, thêm nop

Nhảy không điều kiện theo giá trị thanh ghi

jr rs

trở về hàm gọi, thường dùng jr $ra , PC $ra, cần thêm lệnh delay nop theo sau

Load byte và mở rộng dấu

lb rd, offset(base)

rd byte đã được mở rộng dấu từ ô nhớ có địa chỉ base +

Page 6: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

offset, offset là số bù 2

Load byte và mở rộng số 0 đầu

lbu rd, offset(base)

rd byte đã được mở rộng 0 từ ô nhớ có địa chỉ base + offset, offset là số bù 2

Load half-word và mở rộng dấu

lh rd, offset(base)

rd 2 byte liên tiếp đã được mở rộng dấu từ ô nhớ có địa chỉ base + offset , offset là số bù 2

Load half-word và mở rộng số 0

lhu rd, offset(base)

rd 2 byte liên tiếp đã được mở rộng 0 từ ô nhớ có địa chỉ base + offset, offset là số bù 2

Load hằng vào 16 bit cao

lui rd, const

2 byte cao của rd 16 bit const 2 byte thấp của rd 0x0000

Load word lw rd, offset(base)

rd word bộ nhớ có địa chỉ base + offset, offset là số bù 2

Chuyển giá trị từ hi vào thanh ghi

mfhi rd

rd hi

Chuyển giá trị từ lo vào thanh ghi

mflo rd

rd lo

Nhân hai số bù 2 mult rs, rt

value(hi, lo) rs*rt; rs và rt là hai số bù 2

Nhân hai số không dấu

multu rs, rt

value(hi, lo) rs*rt; rs và rt là hai số không dấu

NOT từng bit nor rd, rs, $0 rd NOT từng bit của rs

NOR từng bit nor rd, rs, rt

rd NOR từng bit của rs và rt

OR từng bit or rd, rs, rt

rd OR từng bit của rs và rt

OR từng bit với hằng 16 bit

or rd, rs, const

rd OR từng bit của rs và hằng sau khi mở rộng 0

Lưu byte thấp của thanh ghi vào bộ nhớ

sb rs, offset(base)

byte ở offset +base byte thấp của rs, offset dạng bù 2

Lưu hai byte thấp vào bộ nhớ

sh rs, offset(base)

2 byte ở offset +base 2 byte thấp của rs, offset dạng bù 2

Lệnh nop sll $0, $0, 0 tạo thời gian trễ cần thiết

Page 7: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

Dịch trái không dấu

sll rd, rs, shft

rd rs sau khi dich trái shft bit; 0 <= shft <32

So sánh hai thanh ghi dạng bù 2

slt rd, rs, rt

if rs < rt rd <-- 1 else rd <-- 0 hai toán hạng dạng bù 2

So sánh thanh ghi với hằng bù 2

slti rd, rs, const

if rs < const rd <-- 1 else rd <-- 0 hai toán hạng dạng bù 2

So sánh thanh ghi với hằng không dấu

sltiu rd, rs, const

if rs < const rd <-- 1 else rd <-- 0 hai toán hạng dạng không dấu

So sánh hai thanh ghi không dấu

sltu rd, rs, rt

if rs < rt rd <-- 1 else rd <-- 0 hai toán hạng dạng không dấu

Dịch phải có dấu sra rd, rs, shft

rd rs sau khi dich phải shft bit và mở rộng dấu; 0 <= shft <32

Dịch phải luận lý srl rd, rs, shft

rd rs sau khi dich phải shft bit; 0 <= shft <32

Trừ hai thanh ghi dạng bù 2

sub rd, rs, rt

rd rs – rt; các toán hạng dạng bù 2

Trừ hai thanh ghi dạng không dấu

subu rd, rs, rt

rd rs – rt; các toán hạng dạng không dấu

Lưu thanh ghi vào bộ nhớ

sw rs, offset(base)

word ở địa chỉ offset + base $rs; offset dạng bù 2

XOR từng bit xor rd, rs, rt

rd XOR từng bit rs và rt

XOR từng bit với hằng

xori rd, rs, rt

rd XOR từng bit rs và hằng sau khi mở rộng 0

Page 8: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

4. Cú pháp của MIPS Assempler

Chú thích (comment) chuỗi các từ bắt đầu bằng #, tất cả các từ bắt đầu từ # cho đến cuối dòng đều được bỏ qua.

Tên định danh (identifier) là chuỗi các ký tự chữ, số, dấu gạch dưới (_) và dấu chấm (.) không bắt đầu bằng số. Tên không được trùng với các từ dành riêng là opcode của lệnh.

Các ví dụ về tên định danh hợp lệ: main, loop, end_if, case1.2 Các ví dụ về tên định danh không hợp lệ: 1value # số đứng đầu b # trùng với opcode lệnh nhảy add # trùng với opcode lệnh cộng Nhãn bao gồm tên định danh theo sau là dấu hai chấm (:) được đặt ở đầu dòng. Ví dụ:

Số (number) mặc định là cơ số 10. Số thập lục phân (hexadecimal) thêm 0x vào phía

trước. Hai số 256 và 0x100 diễn tả số có cùng giá trị. Chuỗi (string) được đặt giữa hai dấu nháy kép (“). Ví dụ: “Hello world!\n”. Các ký tự

đặt biệt cho phép trong chuỗi:

Chỉ thị (directive) được hỗ trợ gồm có:

Tên chỉ thị Ý nghĩa .text <addr> Tất cả các phần theo sau cho tới chỉ thị mới (.text, .ktext, .data, .kdata) được

đặt trong vùng nhớ chương trình (code segment). Tham số addr nếu có quy định địa chỉ bắt đầu của vùng nhớ chương trình dùng để lưu các phần trong phân đoạn mã chương trình này. Phần theo sau thường là các lệnh.

.ktext <addr> Tất cả các phần theo sau cho tới chỉ thị mới (.text, .ktext, .data, .kdata) được đặt vào vùng nhớ nhân (kernel) của hệ điều hành. Tham số addr nếu có quy định địa chỉ bắt đầu của vùng nhớ dùng để lưu. Phần theo sau thường là các lệnh.

.globl sym Khai báo nhãn sym là toàn cục và có thể được tham khảo từ file khác

.data <addr> Tất cả các phần theo sau cho tới chỉ thị mới (.text, .ktext, .data, .kdata) được đặt trong vùng nhớ dữ liệu nhân (kernel data segment). Tham số addr nếu có quy định địa chỉ bắt đầu của vùng nhớ dùng để lưu.

newline \n tab \t quote \”

.data item: .word 1

.text

.globl main # must be global main:

Page 9: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

.kdata <addr> Tất cả các phần theo sau cho tới chỉ thị mới (.text, .ktext, .data, .kdata) được đặt trong vùng nhớ dữ liệu (data segment). Tham số addr nếu có quy định địa chỉ bắt đầu của vùng nhớ dùng để lưu.

.ascii str Lưu chuỗi str vào bộ nhớ, không có ký tự kết thúc chuỗi (giá trị = 0) sau cùng

.asciiz str Lưu chuỗi str vào bộ nhớ, thêm ký tự kết thúc chuỗi (giá trị = 0) sau cùng

.byte b1,..,bn Lưu n byte liên tiếp nhau b1,..,bn vào bộ nhớ

.half h1,..,hn Lưu n phần tử 16-bit liên tiếp nhau h1,..,hn vào bộ nhớ

.word w1,..,wn Lưu n phần tử 32-bit liên tiếp nhau w1,..,wn vào bộ nhớ

.float f1,..,fn Lưu n số thực dấu chấm động độ chính xác đơn liên tiếp nhau f1,..,fn vào bộ nhớ

.double d1,..,dn Lưu n số thực dấu chấm động độ chính xác đơn liên tiếp nhau d1,..,dn vào bộ nhớ

.space n Cấp phát n byte liên tiếp nhau trong phân đoạn dữ liệu hiện tại. Phải đặt sau chỉ thị .data

.extern sym n Khai báo dữ liệu lưu ở sym có kích thước n byte và sym là nhãn toàn cục. Dữ liệu vùng nhớ này được truy xuất thông qua thanh ghi $gp

Page 10: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5. Các chương trình mẫu 5.1 Các lệnh luận lý:

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF

5.2 Các lệnh số học:

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF

add addu div multu addi sub divu mfhi addiu subu mult mflo

and ori nor andi xor sll or xori srl

## Put the bit pattern 0x0000FACE into register $1. .text .globl main main: ori $1,$0,0xFACE # 0x0000FACE into $1 andi $2,$1,0x0F0F # 0x0A0E in $2 andi $3,$1,0x00F0 # 0x00C0 in $3 sll $3,$3,8 # 0xC000 in $3 or $2,$2,$3 # 0xCA0E in $2 andi $3,$1,0xF000 # 0xF000 in $3 srl $3,$3,8 # 0x00F0 in $3 or $2,$2,$3 # 0xCAFE in $3 # done ## End of file

Page 11: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.3 Các lệnh thao tác bộ nhớ

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF

lb lui sb lbu lw sh lh lhu sw

## Program to calculate 3x**2 + 5x - 8 ## ## Assumes that all results fit into 32 bits. ## ## Follows the hardware rule of keeping a new mult ## two instructions away from a previous mflo. ## ## Register Use: ## $8 x ## $9 result .text .globl main main: addiu $8, $0, 1 # put x into $8 mult $8, $8 # lo = x**2 mflo $9 # $9 = x**2 ori $7, $0, 3 # $7 = 3 ori $6, $0, 5 # $6 = 5 mult $7, $9 # lo = 3x**2 mflo $9 # $9 = 3x**2 ori $7, $0, 5 # $7 = 5 addi $9, $9, -8 # $9 = 3x**2 - 8 mult $7, $8 # lo = 5x mflo $7 # $7 = 5x addu $9, $9, $7 # $9 = 3x**2 + 5x - 8 ## End of file

Page 12: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.4 Các lệnh nhảy

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF

j bne slti beq bltz sltu bgez slt sltiu

## Find the Significant bits in a pattern ## The significant bits are the leftmost one bit and ## all its to its right ## Approach: Count the number of right shifts needed ## before the pattern becomes all zeros ## ## Register Use: ## $7 --- shift count ## $8 --- the bit pattern, 0x00298D7D for example. .text .globl main main: ori $8,$0,0x0029 # load $8 with the pattern sll $8,$8,16 # shift into MSBs ori $8,$8,0x8D7D # or in the LSBs

## copy $9 to memory in big-endian form ## ## Register Use: ## $8 --- first byte of the tape block ## $9 --- 4-byte integer .text .globl main main: lui $9,0x1234 # put data in $9 ori $9,0x5678 # lui $8,0x1000 # $8 is base register sb $9,3($8) # least significant byte srl $9,$9,8 # move next byte to low order sb $9,2($8) # bits 8-15 srl $9,$9,8 # move next byte to low order sb $9,1($8) # bits 16-23 srl $9,$9,8 # move next byte to low order sb $9,0($8) # most significant byte .data tape: # base register points here .space 1024 # tape buffer (1K bytes) ## End of file

Page 13: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.5 Các ví dụ xử lý chuỗi, xử lý mảng

Các lệnh đã biết cho đến giờ:

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF

loop: beq $8,$0,exit # done when pattern == 00 sll $0,$0,0 # delay or nop after a branch # or jump instruction srl $8,$8,1 # shift right one bit addu $7,$7,1 # increment shift count j loop # repeat sll $0,$0,0 exit: j exit # sponge for extra cycles sll $0,$0,0 ## End of file

add div mflo slt, slti

addi divu mult sltu, sltiu

addiu j multu sra

addu lb nor srl

and lbu or sub

andi lh ori subu

beq lhu sb sw

bgez lui sh xor

bltz lw sll xori

bne mfhi

## To Lower Case ## ## ## Write a program that converts the string to all lower case ## characters. Do this by adding 0x20 to each character in the string. ## Register Use: ## ## $8 --- current character ## $10 --- character pointer

Page 14: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.6 Các lệnh mã giả mở rộng

Thiết lập các tham số trong menu Simulator -> Settings: SPIM set Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF. Ví dụ theo sau thực hiện việc tính hóa đơn bữa ăn:

tổng phí = tiền thức ăn + 8% tiền thuế +15% tiền phục vụ

.text .globl main main: lui $10,0x1000 # initialize base register of the string lbu $8,($10) # get the first char of the string sll $0,$0,0 loop: beq $8,$0,halt # while ( char != '/0' ) sll $0,$0,0 # addiu $8,$8,0x20 # uncapitalize char sb $8,($10) # replace char in string addiu $10,$10,1 # advance the char pointer lbu $8,($10) # get the next char of the string j loop # end while sll $0,$0,0 halt: j halt # cycle sponge sll $0,$0,0 .data string: .asciiz "ABCDEFGHIJKLMNOP" ## End of file

move d,s # copy the contents of the source register s to the # destination register d li d,value # load register $d with the positive or negative # integer "value". Value may be a 16 or a 32-bit integer. lw d,exp # Load register $d with the value at address "exp". # "exp" is often a symbolic address. la d,exp # load register $d with the address described by the # expression "exp". "exp" is often a symbolic address. nop # no operation. do nothing for one machine cycle. sw d,exp # Store register $d into the word at address exp. # exp can be any of several expression types # that evaluate to an address mul d,s,t # multiply $s by $t. put the result in $d div d,s,t # divide $s by $t. Put the quotient in $d. Operands are # two's complement. divu d,s,t # divide $s by $t. Put the quotient in $d. Operands are # unsigned. remu d,s,t # divide $s by $t. Put the remainder in $d. Operands are # unsigned.

Page 15: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

## rest.asm ## ## Total restaurant bill calculator ## ## Register Use: ## ## $s0 meal cost ## $s1 tip rate ## $s2 tax rate ## $s3 total rate ## $s4 tax+tip dollars ## $s5 total bill .globl main # Get meal cost main: li $v0,4 # print prompt la $a0,prompt syscall li $v0,5 # input meal cost syscall move $s0,$v0 # save it in $s0 # Calculations lw $s1,tip # get tip rate lw $s2,tax # get tax rate addu $s3,$s1,$s2 # (tax + tip) in percent mul $s4,$s0,$s3 # mealcost*(total rate) div $s4,$s4,100 # mealcost*(total rate)/100 addu $s5,$s0,$s4 # total bill # Output li $v0,4 # print string la $a0,head1 # "tax plus tip" syscall move $a0,$s4 # get tax+tip li $v0,1 # print integer syscall # li $v0,4 # print string la $a0,head2 # "total cost" syscall move $a0,$s5 # get total li $v0,1 # print integer syscall # li $v0,10 # exit syscall .data tip: .word 15 # tip rate in percent tax: .word 8 # tax rate in percent prompt: .asciiz "Enter food cost: " head1 : .asciiz " Tax plus tip: " head2 : .asciiz "\n Total cost: "

Page 16: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.7 Các chương trình xử lý xuất nhập SPIM cung cấp các hàm hệ thống dùng để xử lý các thao tác xuất nhập sau:

Công việc Mã trong $v0 Tham số Giá trị trả về

print integer 1 $a0 == integer

print float 2 $f12 == float

print double 3 ($f12, $f13) == double

print string 4 $a0 == address of string

read integer 5 $v0 == integer

read float 6 $f0 == float

read double 7 ($f0, $f1) == double

read string 8 $a0 == buffer address

$a1 == buffer length

allocate memory 9 $a0 == number of bytes $v0 == address

exit 10

Sau đây là ví dụ sử dụng hàm hệ thống để in chuỗi ký tự và kết thúc chương trình:

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File ON, Delayed Branches ON, Delayed Loads ON, Mapped IO OFF, Quiet OFF Ví dụ sau in ra mẫu thư nhắc nhở trả sách một cách tự động sau khi người dùng nhập tên người mượn sách trả trễ:

# hello.asm # .text .globl main main: li $v0,4 # code 4 == print string la $a0,string # $a0 == address of the string syscall # Invoke the exception handler. li $v0,10 # code 10 == exit syscall # Halt the program. .data string: .asciiz "Hello SPIM!\n" # end of file

Page 17: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.8 Dùng stack tính toán biểu thức

Thanh ghi stack pointer ($sp) dùng để quản lý stack. Thanh ghi này chỉ đến phần tử trên đỉnh ở vùng nhớ stack. Khi chương trình bắt đầu chạy, $sp có giá trị khởi tạo 0x7FFFFFFC. Vùng nhớ stack mở rộng xuống dưới đồng nghĩa giá trị thanh ghi $sp giảm đi. Tác vụ PUSH phần tử vào stack tiến hành hai việc: • Thứ nhất, thay đổi giá trị thanh ghi $sp để trỏ đến phần tử đỉnh mới • Thứ hai, lưu giá trị vào vị trí đỉnh mới Tương tự, tác vụ POP phần tử ra stack tiến hành hai việc: • Thứ nhất, lưu giá trị phần tử đỉnh stack vào biến • Thứ hai, thay đổi giá trị thanh ghi $sp trỏ đến phần tử đỉnh mới

# overdue.asm .text .globl main main: # get patron name li $v0,4 # print prompt la $a0,prompt # syscall li $v0,8 # code 8 == read string la $a0,name # $a0 == address of buffer li $a1,24 # $a1 == buffer length syscall # Invoke the operating system. # print the letter li $v0,4 # print greeting la $a0,letter # syscall li $v0,4 # print body la $a0,body # syscall li $v0,10 # exit syscall .data prompt: .asciiz "enter name, followed by comma-enter: " letter: .ascii "\n\nDear " name: .space 24 body: .ascii "\nYour library books are way\n" .ascii "overdue. Please return them\n" .ascii "before we give your name\n" .ascii "to the enforcement squad.\n" # end of file

Page 18: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File ON, Delayed Branches ON, Delayed Loads ON, Mapped IO ON, Quiet OFF

# POP the item into $t0: lw $t0,($sp) # Copy top the item to $t0. addiu $sp,$sp,4 # Point to the item beneath the old top.

# PUSH the item in $t0: addiu $sp,$sp,-4 # point to the place for the new item, sw $t0,($sp) # store the contents of $t0 as the new top.

# Evaluate the expression ab - 12a + 18b - 7 # # Settings: Load delays OFF; Branch delays OFF, # Trap file ON; Pseudoinstructions ON .globl main main: lw $t0,a # get a lw $t1,bb # get b mul $t0,$t0,$t1 # a*b subu $sp,$sp,4 # push a*b onto stack sw $t0,($sp) lw $t0,a # get a li $t1,-12 # mul $t0,$t0,$t1 # -12a subu $sp,$sp,4 # push -12a onto stack sw $t0,($sp) lw $t0,bb # get b li $t1,18 # mul $t0,$t0,$t1 # 18b subu $sp,$sp,4 # push 18b onto stack sw $t0,($sp)

Page 19: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.9 Cách gọi hàm đơn giản

Lệnh jal dùng để gọi hàm, lệnh jr dùng để trở về từ hàm được gọi. Lệnh nop cần được thêm vào sau các lệnh jal và jr

Các chú ý về cách gọi hàm đơn giản:

o Thủ tục con được gọi bởi lệnh jal. o Thủ tục con không gọi thủ tục con khác. o Thủ tục con trở về chương trình gọi bằng lệnh jr $ra. o Các thanh ghi được sử dụng:

$t0 - $t9 — Thủ tục con tự do sử dụng. $s0 - $s7 — Thủ tục con không được thay đổi giá trị sau khi trở về.

jal sub # $ra <― PC+4 (the address 8 bytes away from the jal) # PC <― sub load the PC with the subroutine entry point # a branch delay slot follows this instruction jr $ra # PC <― $ra # A branch delay slot follows this instruction.

li $t1,-7 # init sum to -7 lw $t0,($sp) # pop 18b addu $sp,$sp,4 addu $t1,$t1,$t0 # 18b -7 lw $t0,($sp) # pop -12a addu $sp,$sp,4 addu $t1,$t1,$t0 # -12a + 18b -7 lw $t0,($sp) # pop ab addu $sp,$sp,4 addu $t1,$t1,$t0 # ab - 12a + 18b -7 done: li $v0,1 # print sum move $a0,$t1 syscall li $v0,10 # exit syscall .data a: .word 0 bb: .word 10

Page 20: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

$a0 - $a3 — Chứa các tham số cho thủ tục con. Thủ tục con có thể thay đổi các thanh ghi này.

$v0 - $v1 — Chứa các giá trị trả về từ thủ tục con. o Thủ tục main trả điều khiển bằng cách sử dụng hàm exit của hệ thống.

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File ON, Delayed Branches ON, Delayed Loads ON, Mapped IO ON, Quiet OFF Sau đây là chương trình đọc 3 số nguyên và in ra tổng của chúng:

# read in three integers and print their sum # .text .globl main main: jal pread # read first integer nop # branch delay slot move $s0,$v0 # save it in $s0 jal pread # read second integer nop # branch delay slot move $s1,$v0 # save it in $s1 jal pread # read third integer nop # branch delay slot move $s2,$v0 # save it in $s2 addu $s0,$s0,$s1 # compute the sum addu $a0,$s0,$s2 li $v0,1 # print the sum syscall li $v0,10 # exit syscall # pread -- prompt for and read an integer # on entry: # $ra -- return address # on exit: # $v0 -- the integer .text .globl pread pread: la $a0,prompt # print string li $v0,4 # service 4 syscall li $v0,5 # read int syscall # service 5 jr $ra # return nop # branch delay slot .data prompt: .asciiz "Enter an integer: "

Page 21: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.10 Gọi hàm dùng stack Các chú ý khi một thủ tục gọi một thủ tục con dùng stack:

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File ON, Delayed Branches ON, Delayed Loads ON, Mapped IO ON, Quiet OFF. Sau đây là ví dụ chương trình yêu cầu người dùng nhập vào 2 số X, Y. Chương trình thực hiện việc tính toán các biểu thức X*X, X*Y, 5*Y và in ra kết quả lớn nhất từ giá trị của 3 biểu thức trên. Chương trình main gọi thủ tục con maxExp tính và tìm ra giá trị lớn nhất từ ba biểu thức X*X, X*Y và 5*Y sau khi đã có giá trị X, Y. Thủ tục con maxExp gọi thủ tục con maxInt hai lần để so sánh X*X với X*Y, kết quả sẽ so sánh với 5*Y để cho ra kết quả yêu cầu.

Gọi thủ tục con (thực hiện bởi chương trình gọi):

1. Push vào stack các thanh ghi $t0-$t9 cần lưu giá trị. Thủ tục con có thể thay đổi các thanh ghi này.

2. Gán giá trị vào các tham số của thủ tục con $a0-$a3. 3. Gọi thủ tục con sử dụng jal.

Phần đầu thủ tục con (Trong thủ tục con):

4. Nếu thủ tục con này có thể gọi các thủ tục con khác, phải push $ra vào stack. 5. Push vào stack các thanh ghi $s0-$s7 nếu thủ tục con này có thể thay đổi chúng.

Thân thủ tục con:

6. Thủ tục con có thể thay đổi các thanh ghi T, A hoặc S (nếu như S đã được lưu ở bước 5). 7. Nếu thủ tục con này gọi thủ tục con khác thì nó phải tuân thủ các chú ý này.

Phần cuối thủ tục con (Thực hiện trước khi trở về chương trình gọi):

8. Đưa các giá trị cần trả về vào $v0-$v1 9. Pop ra khỏi stack (theo thứ tự ngược) các thanh ghi $s0-$s7 đã lưu ở bước 5. 10. Pop ra khỏi stack địa chỉ trở về $ra nếu thực hiện bước 4 11. Trở về chương trình gọi sử dụng jr $ra.

Phục hồi điều khiển sau khi trở về từ chương trình con (thực hiện bởi chương trình gọi):

12. Pop ra khỏi stack (theo thứ tự ngươc) các thanh ghi $t0-$t9 đã được push vào stack ở bước 1.

Page 22: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

## Driver -- main program for the application .text .globl main main: sub $sp,$sp,4 # push the return address sw $ra,($sp) sub $sp,$sp,4 # push $s0 sw $s0,($sp) la $a0,xprompt # prompt the user li $v0,4 # service 4 syscall li $v0,5 # service 5 -- read int syscall # $v0 = integer move $s0,$v0 # save x la $a0,yprompt # prompt the user li $v0,4 # service 4 syscall li $v0,5 # service 5 -- read int syscall # $v0 = integer # prepare arguments move $a0,$s0 # x move $a1,$v0 # y jal maxExp # maximum expression nop # returned in $v0 move $s0,$v0 # keep it safe la $a0,rprompt # output title li $v0,4 # service 4 syscall move $a0,$s0 # get maximum li $v0,1 # print it out syscall lw $ra,($sp) # pop $s0 add $s0,$sp,4 lw $ra,($sp) # pop return address add $sp,$sp,4 jr $ra # return to OS nop .data xprompt: .asciiz "Enter a value for x --> " yprompt: .asciiz "Enter a value for y --> " rprompt: .asciiz "The maximum expression is: "

Page 23: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

## maxInt -- compute the maximum of two integer arguments ## ## Input: ## $a0 -- a signed integer ## $a1 -- a signed integer ## ## Returns: ## $v0 -- maximum .text .globl maxInt maxInt: # body move $v0,$a0 # max = $a0 bgt $a0,$a1,endif # if $a1 > $a0 nop move $v0,$a1 # max = $a1 endif: # endif # epilog jr $ra # return to caller nop ## maxExp -- compute the maximum of three expressions ## ## Input: ## $a0 -- a signed integer, x ## $a1 -- a signed integer, y ## ## Returns: ## $v0 -- the maximum of x*x, x*y, or 5*y ## ## Registers: ## $s0 -- x*x ## $s1 -- x*y ## $s2 -- 5*y .text .globl maxInt maxExp: # prolog sub $sp,$sp,4 # push the return address sw $ra,($sp) sub $sp,$sp,4 # push $s0 sw $s0,($sp) sub $sp,$sp,4 # push $s1 sw $s1,($sp) sub $sp,$sp,4 # push $s2 sw $s2,($sp) # body mul $s0,$a0,$a0 # x*x mul $s1,$a0,$a1 # x*y li $t0,5 mul $s2,$t0,$a1 # 5*y move $a0,$s0 # compute max of x*x move $a1,$s1 # and x*y jal maxInt # current max in $v0 nop move $a0,$v0 # compute max of move $a1,$s2 # current max, and 5*y jal maxInt # total max will be in $v0 nop

Page 24: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

5.11 Quản lý biến cục bộ và gọi hàm sử dụng stack pointer và frame pointer Thủ tục con có thể sử dụng stack để tính toán các biểu thức (5.8), thanh ghi sp có thể thay đổi nên khó sử dụng thanh ghi này để quản lý biến cục bộ cố định. Để quản lý biến cục bộ một cách dễ dàng, MIPS sử dụng thanh ghi fp làm địa chỉ nền cố định để quản lý biến cục bộ trong quá trình thực thi. Hình bên minh họa việc dùng thanh ghi fp để quản lý biến cục bộ với các giả sử sau:

• Thủ tục cha gọi thủ tục con; • Thủ tục cha sử dụng các thanh ghi tạm $t0,

$t3 trước khi gọi thủ tục con; • Thủ tục con sử dụng các thanh ghi $s0, $s3,

$s5; • Thủ tục con gồm 4 biến cục bộ a, b, i, j

Các chú ý khi một thủ tục gọi một thủ tục con dùng stack pointer và frame pointer:

Gọi thủ tục con (thực hiện bởi chương trình gọi):

1. Push vào stack các thanh ghi $t0-$t9 cần lưu giá trị. Thủ tục con có thể thay đổi các thanh ghi này.

2. Gán giá trị vào các tham số của thủ tục con $a0-$a3. 3. Gọi thủ tục con sử dụng jal.

Phần đầu thủ tục con (Trong thủ tục con):

4. Push $ra vào stack. 5. Push thanh ghi $fp của thủ tục gọi 6. Push vào stack các thanh ghi $s0-$s7 nếu thủ tục con này có thể thay đổi chúng. 7. Khởi tạo $fp = $sp – không gian cần cho biến cục bộ (4*số biến cục bộ). 8. Khởi tạo $sp = $fp

Thân thủ tục con:

9. Thủ tục con có thể thay đổi các thanh ghi T, A hoặc S (nếu như S đã được lưu ở bước 5). 10. Thủ tục con tham khảo đến biến cục bộ sử dụng offset($fp) 11. Thủ tục con tự do push, pop phần tử vào stack 12. Nếu thủ tục con này gọi thủ tục con khác thì nó phải tuân thủ các chú ý này.

Phần cuối thủ tục con (Thực hiện trước khi trở về chương trình gọi):

13. Đưa các giá trị cần trả về vào $v0-$v1 14. $sp = $fp + không gian cần cho biến cục bộ 15. Pop ra khỏi stack (theo thứ tự ngược) các thanh ghi $s0-$s7 đã lưu ở bước 5. 16. Pop ra khỏi stack địa chỉ trở về $ra. 17. Pop ra khỏi stack địa chỉ trở về $ra

Page 25: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

18. Trở về chương trình gọi sử dụng jr $ra.

Phục hồi điều khiển sau khi trở về từ chương trình con (thực hiện bởi chương trình gọi):

19. Pop ra khỏi stack (theo thứ tự ngươc) các thanh ghi $t0-$t9 đã được push vào stack ở bước 1.

Thiết lập các tham số trong menu Simulator -> Settings: Bare Machine OFF, Allow Pseudo Instructions ON, Load Trap File ON, Delayed Branches ON, Delayed Loads ON, Mapped IO ON, Quiet OFF.

# main() # { # int a, b; // a: 0($fp), b: 4($fp) # write("enter an int:") # read( a ); # b = fact( a ); # write("factorial is:") # print( b ); # } .text .globl main main: addiu $sp,$sp,-4 sw $ra,0($sp) # 1. Push return address addiu $sp,$sp,-4 sw $fp,0($sp) # 2. Push caller's frame pointer # 3. No S registers to push addiu $fp,$sp,-8 # 4. $fp = $sp - space_for_variables addu $sp,$fp,$0 # 5. $sp = $fp li $v0,4 # write("enter an int:") la $a0,prompt1 syscall li $v0,5 # read( a ) syscall # subroutine call # 1. No T registers to push addu $a0,$v0,$0 # 2. Put argument into $a0 jal fact # 3. Jump and link to subroutine nop # return from subroutine # 1. No T registers to restore sw $v0,4($fp) # b = fact( a )

Page 26: Huong Dan Thuc Hanh MIPS ASM Tren PCSpim

li $v0,4 # write("factorial is:") la $a0,prompt2 syscall lw $a0,4($fp) # print( b ) li $v0,1 syscall # epilog # 1. No return value addu $sp,$sp,8 # 2. $sp = $fp + space_for_variables # 3. No S registers to pop lw $fp,0($sp) # 4. Pop $fp lw $ra,4($sp) # 5. Pop $ra addu $sp,$sp,8 jr $ra # return to OS nop .data prompt1: .asciiz "enter an int:" prompt2: .asciiz "factorial is:" # int fact( int n ) # { # if ( n <= 1 ) # return 1; # else # return n*fact(n-1); # } .text .globl fact fact: addiu $sp,$sp,-8 # adjust stack for 2 items sw $ra,0($sp) # save return address sw $a0,4($sp) # save argument #addi $t0,$0,2 slti $t0,$a0,2 # test for n < 2 beq $t0,$0,else addi $v0,$0,1 # if so, result is 1 addiu $sp,$sp,8 # pop 2 items from stack jr $ra # and return nop else: addi $a0,$a0,-1 # else decrement n jal fact # recursive call nop lw $a0,4($sp) # restore original n lw $ra,0($sp) # and return address addi $sp,$sp,8 # pop 2 items from stack mul $v0,$v0,$a0 # multiply to get result jr $ra # and return nop