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…
•
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.
•
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)
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.
3. Tập lệnh của MIPS
Lệnh
Cộng số bù 2
Cộng không dấu
Cộng với hằng số
16 bit bù 2
Cộng với hằng số
16 bit không dấu
AND từng bit
AND từng bit với
hằng số 16 bit
Nhảy nếu bằng
Nhảy nếu lớn hơn
hay bằng 0
Cú pháp
add rd, rs, rt
addu rd, rs, rt
addi rd, rs, const
addiu rd, rs, const
and rd, rs, rt
andi rd, rs, const
beq rs, rt, addr
bgez rs, addr
Định dạng lệnh
Ý nghĩa
rd < rs+rt ;
rd < rs+rt ;
rd
rd
rd
rs+const ;
rs+const ;
bitwise AND of rs with rt
rd bitwise AND of rs with
const
nhảy đến addr nếu rs == rt. Cần
phải thêm delay theo sau (nop)
nhảy đến addr nếu số bù 2 trong
rs >= 0. Cần thêm delay
nhảy đến addr nếu số bù 2 trong
rs < 0. Cần thêm delay
nhảy đến addr nếu rs != rt. Cần
thêm delay
lo rs div rt; hi rs mod rt
hai số rs và rt ở dạng bù 2
lo rs div rt; hi rs mod rt
hai số rs và rt ở dạng không dấu
delay sau một chu kỳ máy:
PC địa chỉ của target
gọi hàm target, $ra = PC +4
PC địa chỉ của target, thêm
nop
trở về hàm gọi, thường dùng
jr $ra , PC $ra, cần thêm lệnh
delay nop theo sau
rd byte đã được mở rộng dấu
từ ô nhớ có địa chỉ base +
Nhảy nếu nhỏ hơn bltz rs, addr
0
Nhảy nếu khác
Chia hai số bù 2
Chia hai số không
dấu
Nhảy không điều
kiện
Nhảy không điều
kiện và link
Nhảy không điều
kiện theo giá trị
thanh ghi
Load byte và mở
rộng dấu
bne rs, rt, addr
div rs, rt
divu rs, rt
j target
jal target
jr rs
lb rd, offset(base)
offset, offset là số bù 2
Load byte và mở
rộng số 0 đầu
Load half-word
và mở rộng dấu
Load half-word
và mở rộng số 0
Load hằng vào 16
bit cao
Load word
Chuyển giá trị từ
hi vào thanh ghi
Chuyển giá trị từ
lo vào thanh ghi
Nhân hai số bù 2
Nhân hai số
không dấu
NOT từng bit
NOR từng bit
OR từng bit
OR từng bit với
hằng 16 bit
Lưu byte thấp của
thanh ghi vào bộ
nhớ
Lưu hai byte thấp
vào bộ nhớ
Lệnh nop
lbu rd, offset(base)
rd byte đã được mở rộng 0 từ
ô nhớ có địa chỉ base + offset,
offset là số bù 2
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
rd 2 byte liên tiếp đã được
mở rộng 0 từ ô nhớ có địa chỉ
base + offset, offset là số bù 2
2 byte cao của rd
2 byte thấp của rd
16 bit const
0x0000
lh rd, offset(base)
lhu rd, offset(base)
lui rd, const
lw rd, offset(base)
mfhi rd
mflo rd
mult rs, rt
multu rs, rt
nor rd, rs, $0
nor rd, rs, rt
or rd, rs, rt
or rd, rs, const
sb rs, offset(base)
rd word bộ nhớ có địa chỉ
base + offset, offset là số bù 2
rd
rd
hi
lo
rs*rt; rs và rt là
value(hi, lo)
hai số bù 2
value(hi, lo) rs*rt; rs và rt là
hai số không dấu
rd
rd
rd
NOT từng bit của rs
NOR từng bit của rs và rt
OR từng bit của rs và rt
rd OR từng bit của rs và
hằng sau khi mở rộng 0
byte ở offset +base byte thấp
của rs, offset dạng bù 2
sh rs, offset(base)
sll $0, $0, 0
2 byte ở offset +base 2 byte
thấp của rs, offset dạng bù 2
tạo thời gian trễ cần thiết
Dịch trái không
dấu
So sánh hai thanh
ghi dạng bù 2
sll rd, rs, shft
rd rs sau khi dich trái shft
bit; 0 <= shft <32
if rs < rt
rd < 1
else
rd < 0
slt rd, rs, rt
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
rd rs sau khi dich phải shft
bit; 0 <= shft <32
rd rs – rt; các toán hạng dạng
bù 2
rd rs – rt; các toán hạng dạng
không dấu
word ở địa chỉ offset + base
$rs; offset dạng bù 2
rd
XOR từng bit rs và rt
Dịch phải luận lý
Trừ hai thanh ghi
dạng bù 2
Trừ hai thanh ghi
dạng không dấu
Lưu thanh ghi vào
bộ nhớ
XOR từng bit
XOR từng bit với
hằng
srl rd, rs, shft
sub rd, rs, rt
subu rd, rs, rt
sw rs, offset(base)
xor rd, rs, rt
xori rd, rs, rt
rd XOR từng bit rs và hằng
sau khi mở rộng 0
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ụ:
.data
item:
main:
.text
.globl
…
.word
1
main # must be global
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:
newline
tab
quote
\n
\t
\”
Chỉ thị (directive) được hỗ trợ gồm có:
Tên chỉ thị
.text <addr>
.ktext <addr>
.globl sym
.data <addr>
Ý nghĩa
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.
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.
Khai báo nhãn sym là toàn cục và có thể được tham khảo từ file khác
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.
.kdata <addr>
.ascii str
.asciiz str
.byte b1, ,bn
.half h1, ,hn
.word w1, ,wn
.float f1, ,fn
.double d1, ,dn
.space n
.extern sym n
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.
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
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
Lưu n byte liên tiếp nhau b1, ,bn vào bộ nhớ
Lưu n phần tử 16-bit liên tiếp nhau h1, ,hn vào bộ nhớ
Lưu n phần tử 32-bit liên tiếp nhau w1, ,wn vào bộ nhớ
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ớ
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ớ
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
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
5. Các chương trình mẫu
5.1 Các lệnh luận lý:
and
andi
or
ori
xor
xori
nor
sll
srl
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
##
Put the bit pattern 0x0000FACE into register $1.
.text
.globl main
main:
ori$1,$0,0xFACE# 0x0000FACE into $1
andi
andi
sll
or
andi
srl
or
$2,$1,0x0F0F
$3,$1,0x00F0
$3,$3,8
$2,$2,$3
$3,$1,0xF000
$3,$3,8
$2,$2,$3
# 0x0A0E in $2
# 0x00C0 in $3
# 0xC000 in $3
# 0xCA0E in $2
#
#
#
#
0xF000 in $3
0x00F0 in $3
0xCAFE in $3
done
## End of file
5.2 Các lệnh số học:
add
addi
addiu
addu
sub
subu
div
divu
mult
multu
mfhi
mflo
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
##
##
##
##
##
##
##
##
##
##
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:
$8x
$9result
.text
.globl
main
$8,
$8,
$9
$7,
$6,
$7,
$9
$7,
$9,
$7,
$7
$9,
$0,
$8
$0,
$0,
$9
1
3
5
#
#
#
#
#
#
#
#
#
#
#
#
put x into $8
lo = x**2
$9 = x**2
$7 = 3
$6 = 5
lo = 3x**2
$9 = 3x**2
$7 = 5
$9 = 3x**2 - 8
lo = 5x
$7 = 5x
$9 = 3x**2 + 5x - 8
main:
addiu
mult
mflo
ori
ori
mult
mflo
ori
addi
mult
mflo
addu
$0, 5
$9, -8
$8
$9, $7
## End of file
5.3 Các lệnh thao tác bộ nhớ
lb
lbu
lh
lui
lw
lhu
sb
sh
sw
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
##
##
##
##
##
copy $9 to memory in big-endian form
Register Use:
$8 first byte of the tape block
$9 4-byte integer
.text
.globl
main
#
#
#
#
#
#
#
#
#
#
put data in $9
$8 is base register
least significant byte
move next byte to low order
bits 8-15
move next byte to low order
bits 16-23
move next byte to low order
most significant byte
main:
lui
ori
lui
sb
srl
sb
srl
sb
srl
sb
$9,0x1234
$9,0x5678
$8,0x1000
$9,3($8)
$9,$9,8
$9,2($8)
$9,$9,8
$9,1($8)
$9,$9,8
$9,0($8)
tape:
.data
.space 1024
# base register points here
# tape buffer (1K bytes)
## End of file
5.4
Các lệnh nhảy
j
beq
bgez
bne
bltz
slt
slti
sltu
sltiu
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
##
##
##
##
##
##
##
##
##
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:
ori
sll
ori
main
# load $8 with the pattern
# shift into MSBs
# or in the LSBs
$8,$0,0x0029
$8,$8,16
$8,$8,0x8D7D
loop: beq
sll
srl
addu
j
sll
exit: j
sll
$8,$0,exit
$0,$0,0
$8,$8,1
$7,$7,1
loop
$0,$0,0
exit
$0,$0,0
#
#
#
#
#
done when pattern == 00
delay or nop after a branch
or jump instruction
shift right one bit
increment shift count
# repeat
# sponge for extra cycles
## End of file
5.5
Các ví dụ xử lý chuỗi, xử lý mảng
Các lệnh đã biết cho đến giờ:
add
addi
addiu
addu
and
andi
beq
bgez
bltz
bne
div
divu
j
lb
lbu
lh
lhu
lui
lw
mfhi
mflo
mult
multu
nor
or
ori
sb
sh
sll
slt, slti
sltu, sltiu
sra
srl
sub
subu
sw
xor
xori
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
## 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
.text
.globl
main:
lui
lbu
sll
loop:
beq
sll
addiu
sb
addiu
lbu
j
sll
halt:
j
sll
.data
.asciiz
main
$10,0x1000
$8,($10)
$0,$0,0
$8,$0,halt
$0,$0,0
$8,$8,0x20
$8,($10)
$10,$10,1
$8,($10)
loop
$0,$0,0
halt
$0,$0,0
"ABCDEFGHIJKLMNOP"
# initialize base register of the string
# get the first char of the string
# while ( char != '/0' )
#
#uncapitalize char
#replace char in string
#advance the char pointer
#get the next char of the string
# end while
# cycle sponge
string:
## End of file
5.6
Các lệnh mã giả mở rộng
move d,s
li
lw
la
nop
sw
d,exp
d,value
d,exp
d,exp
#
#
#
#
#
#
#
#
#
#
#
#
copy the contents of the source register s to the
destination register d
load register $d with the positive or negative
integer "value". Value may be a 16 or a 32-bit integer.
Load register $d with the value at address "exp".
"exp" is often a symbolic address.
load register $d with the address described by the
expression "exp". "exp" is often a symbolic address.
no operation. do nothing for one machine cycle.
Store register $d into the word at address exp.
exp can be any of several expression types
that evaluate to an address
mul
div
d,s,t
d,s,t
# multiply $s by $t. put the result in $d
#
#
#
#
#
#
divide $s by $t. Put the quotient in $d. Operands are
two's complement.
divide $s by $t. Put the quotient in $d. Operands are
unsigned.
divide $s by $t. Put the remainder in $d. Operands are
unsigned.
divu d,s,t
remu d,s,t
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ụ
## 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:
main
# print prompt
# input meal cost
# save it in $s0
#
#
#
#
#
#
get tip rate
get tax rate
(tax + tip) in percent
mealcost*(total rate)
mealcost*(total rate)/100
total bill
# Get meal cost
li$v0,4
la$a0,prompt
syscall
li$v0,5
syscall
move$s0,$v0
# Calculations
lw$s1,tip
lw$s2,tax
addu$s3,$s1,$s2
mul$s4,$s0,$s3
div$s4,$s4,100
addu$s5,$s0,$s4
# Output
li$v0,4
la$a0,head1
syscall
move$a0,$s4
li$v0,1
syscall
li$v0,4
la$a0,head2
syscall
move$a0,$s5
li$v0,1
syscall
li$v0,10
syscall
# print string
# "tax plus tip"
# get tax+tip
# print integer
#
# print string
# "total cost"
# get total
# print integer
#
# exit
tip:
tax:
.data
.word
.word
15
8
# tip rate in percent
# tax rate in percent
prompt: .asciiz "Enter food cost: "
head1 : .asciiz "Tax plus tip: "
head2 : .asciiz "\nTotal cost: "
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ệcMã trong $v0Tham sốGiá trị trả về
print integer
print float
print double
print string
read integer
read float
read double
read string
1
2
3
4
5
6
7
8
$a0 == buffer address
$a1 == buffer length
allocate memory
exit
9
10
$a0 == number of bytes
$v0 == address
$a0 == integer
$f12 == float
($f12, $f13) == double
$a0 == address of string
$v0 == integer
$f0 == float
($f0, $f1) == double
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:
# hello.asm
#
.text
.globl main
main:
li$v0,4
la$a0,string
syscall
li$v0,10
syscall
.data
string: .asciiz
# end of file
# code 4 == print string
# $a0 == address of the string
# Invoke the exception handler.
# code 10 == exit
# Halt the program.
"Hello SPIM!\n"
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ễ:
# overdue.asm
.text
.globl
main:
main
# get patron name
li$v0,4
la$a0,prompt
syscall
li$v0,8
la$a0,name
li$a1,24
syscall
# print
li
la
syscall
li
la
syscall
the letter
$v0,4
$a0,letter
$v0,4
$a0,body
# print prompt
#
#
#
#
#
code 8
$a0 ==
$a1 ==
Invoke
== read string
address of buffer
buffer length
the operating system.
# print greeting
#
# print body
#
# exit
li$v0,10
syscall
.data
prompt: .asciiz "enter name, followed by comma-enter: "
letter: .ascii "\n\nDear "
name:.space 24
body:
.ascii
.ascii
.ascii
.ascii
"\nYour library books are way\n"
"overdue. Please return them\n"
"before we give your name\n"
"to the enforcement squad.\n"
# end of file
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
# PUSH the item in $t0:
addiu $sp,$sp,-4#
sw$t0,($sp)#
point to the place for the new item,
store the contents of $t0 as the new top.
# 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.
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
# Evaluate the expression ab - 12a + 18b - 7
#
# Settings: Load delays OFF; Branch delays OFF,
#Trap fileON; Pseudoinstructions ON
main:
.globl
lw
lw
mul
subu
sw
lw
li
mul
subu
sw
lw
li
mul
subu
sw
main
$t0,a
$t1,bb
$t0,$t0,$t1
$sp,$sp,4
$t0,($sp)
$t0,a
$t1,-12
$t0,$t0,$t1
$sp,$sp,4
$t0,($sp)
$t0,bb
$t1,18
$t0,$t0,$t1
$sp,$sp,4
$t0,($sp)
#
#
#
#
get a
get b
a*b
push a*b onto stack
# get a
#
# -12a
# push -12a onto stack
# get b
#
# 18b
# push 18b onto stack
li
lw
addu
addu
lw
addu
addu
lw
addu
addu
done:
$t1,-7
$t0,($sp)
$sp,$sp,4
$t1,$t1,$t0
$t0,($sp)
$sp,$sp,4
$t1,$t1,$t0
$t0,($sp)
$sp,$sp,4
$t1,$t1,$t0
# init sum to -7
# pop 18b
# 18b -7
# pop -12a
# -12a + 18b -7
# pop ab
# ab - 12a + 18b -7
# print sum
# exit
li$v0,1
move$a0,$t1
syscall
li$v0,10
syscall
.data
.word
.word
0
10
a:
bb:
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
jal sub
jr
$ra
#
#
#
#
#
$ra <― PC+4 (the address 8 bytes away from the jal)
PC <― subload the PC with the subroutine entry point
a branch delay slot follows this instruction
PC <― $ra
A branch delay slot follows this instruction.
Các chú ý về cách gọi hàm đơn giản:
o
o
o
o
Thủ tục con được gọi bởi lệnh jal.
Thủ tục con không gọi thủ tục con khác.
Thủ tục con trở về chương trình gọi bằng lệnh jr $ra.
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ề.