System Calls (ecall)
คำสั่ง ecall ใน RISC-V ใช้สำหรับขอบริการจากระบบ — ใน Ripes ใช้สำหรับพิมพ์ข้อความออกหน้าจอและสั่งหยุด simulator
หลักการใช้งาน
การเรียก ecall ใน Ripes มี 3 ขั้นตอน:
- ใส่ service number ลงใน register
a7— เป็นเลขที่บอกว่าจะขอบริการอะไร - ใส่ argument (ถ้ามี) ลงใน register
a0 - เรียกคำสั่ง
ecall
ตาราง System Call ที่รองรับ
a7 | ชื่อ | a0 | ผลลัพธ์ |
|---|---|---|---|
| 1 | print_int | เลขจำนวนเต็ม | พิมพ์เลข signed integer ใน a0 ออกหน้าจอ |
| 2 | print_float | เลขทศนิยม | พิมพ์เลขทศนิยมใน a0 ออกหน้าจอ |
| 4 | print_string | pointer ไปยัง string | พิมพ์ null-terminated string ที่ a0 ชี้อยู่ |
| 10 | exit | — | หยุด simulator |
| 11 | print_char | เลข ASCII | พิมพ์ตัวอักษรตามค่า ASCII ใน a0 |
| 34 | print_hex | เลข | พิมพ์เป็นเลขฐาน 16 |
| 35 | print_bin | เลข | พิมพ์เป็นเลขฐาน 2 |
| 36 | print_unsigned | เลข | พิมพ์เป็น unsigned integer |
| 93 | exit | status code | หยุด simulator พร้อม exit code |
หาดูตารางในโปรแกรม
Ripes เวอร์ชัน 2.1.0 ขึ้นไปมีตาราง ecall ในเมนู
Help → System calls ในตัวโปรแกรม
ตัวอย่างที่ 1: พิมพ์เลขจำนวนเต็ม
.text
li a0 42 # โหลดค่า 42 เข้า a0
li a7 1 # ecall service 1 = print_int
ecall # พิมพ์ "42" ออก Output
ตัวอย่างที่ 2: พิมพ์ตัวอักษร
.text
li a0 42 # โหลดค่า 42 เข้า a0
li a7 11 # ecall service 11 = print_char
ecall # พิมพ์ "*" (เพราะ ASCII 42 = '*')
ตัวอย่างที่ 3: พิมพ์ string
.data
str: .string "Hello, RISC-V!"
.text
la a0 str # โหลด address ของ str เข้า a0
li a7 4 # ecall service 4 = print_string
ecall # พิมพ์ "Hello, RISC-V!"
คำสั่ง
la (load address)
la เป็น pseudo-instruction ของ RISC-V ที่จะถูกแปลเป็นชุดคำสั่ง lui + addi ใช้สำหรับโหลด address ของ label เข้า register
ตัวอย่างที่ 4: หยุด simulator
.text
main:
li a7 10
ecall # หยุด simulator ตรงนี้
# คำสั่งหลัง ecall จะไม่ถูก execute
li a1 1
li a2 1
li a3 1
อีกวิธีในการหยุด simulator คือให้โปรแกรม branch ไปยัง label ที่อยู่ท้าย .text segment เพื่อให้ PC ชี้ไปที่ตำแหน่งว่าง
ตัวอย่างที่ 5: รวมหลาย ecall
.data
str1: .string "Result is "
.text
main:
# พิมพ์ "Result is "
la a0 str1
li a7 4
ecall
# พิมพ์เลข 100
li a0 100
li a7 1
ecall
# ขึ้นบรรทัดใหม่ด้วย newline (ASCII 10)
li a0 10
li a7 11
ecall
# ออกจากโปรแกรม
li a7 10
ecall
ผลลัพธ์ใน Output console:
Result is 100
การใช้ ecall ในภาษา C (โหมด -nostdlib)
เมื่อ compile โดยไม่ใช้ standard library สามารถสร้าง wrapper function เรียก ecall ได้ดังนี้:
void prints(volatile char* ptr) {
// ptr ถูกส่งผ่าน register a0 อยู่แล้วตาม ABI
asm("li a7, 4");
asm("ecall");
}
void print_int(int val) {
// val ถูกส่งผ่าน a0 อยู่แล้ว
asm("li a7, 1");
asm("ecall");
}
int main() {
prints("Answer: ");
print_int(42);
return 0;
}