System Calls (ecall)

คำสั่ง ecall ใน RISC-V ใช้สำหรับขอบริการจากระบบ — ใน Ripes ใช้สำหรับพิมพ์ข้อความออกหน้าจอและสั่งหยุด simulator

หลักการใช้งาน

การเรียก ecall ใน Ripes มี 3 ขั้นตอน:

  1. ใส่ service number ลงใน register a7 — เป็นเลขที่บอกว่าจะขอบริการอะไร
  2. ใส่ argument (ถ้ามี) ลงใน register a0
  3. เรียกคำสั่ง ecall

ตาราง System Call ที่รองรับ

a7ชื่อa0ผลลัพธ์
1print_intเลขจำนวนเต็มพิมพ์เลข signed integer ใน a0 ออกหน้าจอ
2print_floatเลขทศนิยมพิมพ์เลขทศนิยมใน a0 ออกหน้าจอ
4print_stringpointer ไปยัง stringพิมพ์ null-terminated string ที่ a0 ชี้อยู่
10exitหยุด simulator
11print_charเลข ASCIIพิมพ์ตัวอักษรตามค่า ASCII ใน a0
34print_hexเลขพิมพ์เป็นเลขฐาน 16
35print_binเลขพิมพ์เป็นเลขฐาน 2
36print_unsignedเลขพิมพ์เป็น unsigned integer
93exitstatus 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;
}