23 điểm bởi GN⁺ 2025-10-28 | 2 bình luận | Chia sẻ qua WhatsApp
  • Đây là một hướng dẫn tương tác giúp học hợp ngữ RISC-V từng bước thông qua trình giả lập có thể chạy trong trình duyệt web, được tạo ra với cảm hứng từ Easy 6502 của Nick Morgan
  • Bao quát 45 lệnh cơ bản của bộ lệnh RV32I_Zicsr và các khái niệm cốt lõi của kiến trúc đặc quyền, giảng dạy một tập lệnh đủ hoàn chỉnh để làm mục tiêu cho trình biên dịch
  • Cung cấp nền tảng của lập trình hợp ngữ như phép toán số học/lôgic, nhánh/nhảy, truy cập bộ nhớ, quy ước gọi hàm, quản lý stack, kèm theo các ví dụ thực hành
  • Giải thích bằng mã thực tế cách chuyển đổi mức đặc quyền giữa chế độ Machine và User, xử lý ngoại lệ, và thao tác CSR (thanh ghi điều khiển và trạng thái)
  • Mục tiêu cuối cùng của hướng dẫn là tự tay viết một hệ điều hành siêu nhỏ hỗ trợ system call và xử lý ngoại lệ, cho phép trải nghiệm toàn bộ quy trình phát triển mức thấp với RISC-V

Cấu trúc hướng dẫn và nội dung học chính

Các lệnh cơ bản và khái niệm về bộ xử lý

  • Trạng thái bộ xử lý: hiểu bộ đếm chương trình (pc), 31 thanh ghi đa dụng (x1~x31), và thanh ghi zero đặc biệt (x0)
  • Lệnh số học: học phép cộng/trừ và hành vi tràn số thông qua add, addi, sub
  • Phép toán bit: thực hành các phép lôgic theo bit và lệnh dịch như and, or, xor, sll, srl, sra
  • Lệnh so sánh: dùng slt, sltu để triển khai so sánh số nguyên có dấu/không dấu và logic điều kiện

Luồng điều khiển và bộ nhớ

  • Nhánh và nhảy: cơ chế gọi hàm và nhánh có điều kiện/vô điều kiện bằng beq, bne, blt, jal, jalr
  • Truy cập bộ nhớ: thao tác load/store theo word/halfword/byte bằng các lệnh lw, sw, lb, lh, sb, sh
  • I/O ánh xạ bộ nhớ: hiểu cách giao tiếp với thiết bị bên ngoài bằng đọc/ghi tới các địa chỉ cụ thể
  • Mã độc lập vị trí: kỹ thuật viết mã có thể tái định vị bằng lệnh auipc và định địa chỉ tương đối theo PC

Hàm và quy ước gọi

  • Bí danh thanh ghi: vai trò của a0~a7 (đối số), s0~s11 (bảo toàn), t0~t6 (tạm thời), ra (địa chỉ trả về), sp (con trỏ stack)
  • Quản lý stack: mẫu lưu thanh ghi khi vào hàm, cấp phát/giải phóng không gian stack, bảo toàn và khôi phục địa chỉ trả về
  • Hàm đệ quy: thực hành gọi đệ quy và quản lý stack frame qua việc cài đặt dãy Fibonacci

Kiến trúc đặc quyền và hệ điều hành

  • Mức đặc quyền: sự khác biệt và cơ chế cách ly giữa chế độ Machine (mức 3) và User (mức 0)
  • Lệnh CSR: đọc/ghi thanh ghi điều khiển và thao tác bit field bằng csrrw, csrrs, csrrc
  • Xử lý ngoại lệ: kiểm tra thông tin ngoại lệ và viết handler thông qua các CSR mcause, mepc, mtval, mstatus
  • Chuyển chế độ: vào và quay lại chế độ User bằng lệnh mret, dùng mscratch cho context switching

Dự án cuối: OS siêu nhỏ

  • Cài đặt system call: trap từ chế độ User sang Machine bằng lệnh ecall để cung cấp chức năng putchar/exit
  • Lưu/khôi phục thanh ghi: toàn bộ cấu trúc trap handler sao lưu và khôi phục mọi thanh ghi đa dụng trên stack
  • Logic xử lý ngoại lệ: phân biệt nguyên nhân ngoại lệ bằng mcause, điều phối theo số system call (a7) và in thông báo lỗi
  • Mã có thể chạy được: cung cấp mã đầy đủ để vào/thoát kernel OS, có thể chạy trực tiếp trong trình giả lập web

Tài liệu tham khảo và giấy phép

  • Cả hướng dẫn và mã nguồn đều theo CC0 public domain hoặc giấy phép BSD 0 điều khoản
  • Bản gốc và kho mã: https://github.com/dramforever/easyriscv
  • Phù hợp để học RISC-V, giáo dục, nghiên cứu và xây dựng môi trường mô phỏng

2 bình luận

 
lsdcnu 2025-11-06

Wow
Mình bắt đầu thấy hứng thú với hợp ngữ RISC-V học trong môn chuyên ngành.. Định mua riêng sách để xem mà chỉ thấy kiến trúc ARM chứ không có RISC-V, nên đang băn khoăn không biết nên học gì thì lại tìm được một tài liệu quá tuyệt vời để học
Cảm ơn nhiều!!!

 
GN⁺ 2025-10-28
Ý kiến trên Hacker News
  • Đây thực sự là một hướng dẫn rất hay
    Tôi ước gì màn hình giả lập đầu tiên của “My first RISC-V assembly program” được đặt ngay ở đầu bài hướng dẫn. Nếu không thì dù tiêu đề là ‘interactive’, độc giả vẫn có thể lầm tưởng đây chỉ là phần giới thiệu toàn chữ
    Tôi dự định sẽ dành thêm vài ngày để tìm hiểu tiếp. Tôi khá quan tâm đến RISC-V và nghĩ rằng nó có một tương lai tươi sáng
    Nếu có chuyên gia AI nào đọc bài này, sẽ thật tuyệt nếu ai đó làm lại Core War bằng RISC-V assembly trên các nền tảng như Replit hoặc Lovable

    • Sao không làm luôn bằng não trực tiếp đi?
  • Tôi học assembly qua Computer Organization And Design của Patterson và Hennessy, nên cảm nhận rất rõ RISC-V đã lấy bao nhiêu thứ từ MIPS
    Cả hai ISA đều có sự tham gia của cùng một số người, và đã tránh được những sai lầm như delay slot của MIPS. Nếu đã có kinh nghiệm với MIPS thì RISC-V assembly gần như cho cảm giác rất giống
    Dạo này tôi cũng đang xem AArch64, và dù nó kém gọn gàng hơn RISC-V, thiết kế thực dụng của nó vẫn rất ấn tượng. Thậm chí tôi còn tự hỏi liệu RISC-V có bị thiết kế quá bảo thủ hay không

    • Có lẽ RISC-V gần với RISC-1 hơn. Có bài viết do chính Patterson giải thích: How close is RISC-V to RISC-I, RISC on a Chip
    • Tôi cũng thấy sự tương đồng giữa RISC-V và MIPS. Khi làm homebrew cho Nintendo 64, tôi thường nghĩ kiểu “cái này gần như y hệt thứ mình từng nghịch trên Ares+Godbolt trước đây, chỉ là không có delay slot thôi”
    • Mọi người dường như chưa nhận ra rằng có khá nhiều điểm không rõ ràng về việc thiết kế của AArch64 bắt nguồn từ đâu và nó được tạo ra theo triết lý nào
    • Thêm lệnh thì dễ, nhưng bỏ lệnh thì khó. RISC-V ban đầu khởi đầu với tập lệnh tối thiểu, rồi sau đó mở rộng dần từng bước. Muốn đề xuất lệnh mới thì phải chứng minh được chi phí và lợi ích thực tế của nó
    • Tôi nhớ là Computer Architecture: A Quantitative Approach cũng có nhắc đến sự tương đồng giữa RISC-V và MIPS. Giờ sách đang nằm trong thùng nên tôi không nhớ chính xác trang nào
  • Tôi đã tự viết TCP Socket in RISC-V Assembly
    Nó dùng ISA RV64I, và bạn cần hiểu khái niệm linker relaxation. Tôi cũng đính kèm tài liệu tham khảo

  • Có vẻ phần Position Independence có lỗi
    Tôi đang thắc mắc liệu trong mã ví dụ có phải nên dùng lui thay vì auipc thì mới ra 0x3004 không

    • Không phải vậy. lui tạo địa chỉ tuyệt đối, còn cặp auipc/addi tạo địa chỉ độc lập vị trí. Nếu auipc nằm ở địa chỉ 0 thì kết quả sẽ giống nhau, nhưng trên thực tế nó là giá trị được cộng thêm với địa chỉ của lệnh hiện tại
  • Cách tổ chức mang tính tương tác của nội dung này thực sự xuất sắc
    Là một lập trình viên C/C++, tôi luôn thấy assembly rất khó, nhưng nhờ cách làm này mà tôi hiểu nó rõ ràng hơn nhiều

    • RISC-V assembly nhìn chung khá dễ, nhưng có quá nhiều tên viết tắt lệnh nên khá khó chịu. Đáng ra có thể dùng những tên trực quan hơn như load4 thay cho lw, hay jump thay cho j, vậy mà không hiểu sao lại phải viết ngắn thế này, đâu còn thời đại thẻ đục lỗ nữa
  • Bài này khiến tôi muốn thử lại lập trình mức thấp
    Tôi từng học mechatronics ở đại học và làm việc với vi điều khiển bằng C và assembly, nhưng giờ đã chuyển sang phát triển web
    Tôi đang tự hỏi có tài liệu đáng tin cậy nào để học phần cứng RISC-V không. Nếu có thể thì tôi muốn thử bằng Rust

    • Không phải là làm phần cứng trực tiếp bằng Rust, nhưng có một tutorial rất hay về các nền tảng OS: Operating System in 1000 Lines
      Ngoài ra còn có một tutorial OS dùng Rust nữa, nhưng hiện tôi chưa tìm lại được liên kết
      Nếu muốn đụng tới phần cứng thực sự thì tôi khuyên dùng neorv32 — tài liệu của nó rất tốt: tài liệu chính thức, kho GitHub. Đây là một lõi RISC-V viết bằng VHDL
  • Phần cứng RISC-V khá dễ kiếm
    Xem RISC-V on Raspberry Pi Pico 2

    • VisionFive 2 Lite cũng sắp ra mắt nên tôi đang khá mong đợi. Về driver hay hiệu năng thì còn hơi thiếu, nhưng để phát triển OS có lẽ vẫn ổn
      Xem trang Kickstarter
      Ngoài ra nếu bạn muốn làm với cả RISC-V và FPGA thì còn có PolarFireSoC. Nó rẻ hơn AMD/Xilinx rất nhiều mà vẫn dùng được. Môi trường phát triển hơi cổ nhưng nhanh, tài liệu thì rải rác nhưng phần lớn vẫn có đâu đó
      liên kết bộ kit phát triển
      Điều thú vị là bo mạch phát triển còn rẻ hơn cả con chip
    • Có lẽ bắt đầu với ESP-32 sẽ dễ hơn. Nó phổ biến hơn nhiều nên cũng dễ kiếm hơn
  • Đúng lúc tuần này khóa học C của tôi bước vào phần nhập môn assembly, và tôi đã nghĩ rằng học bằng RISC-V có thể tránh được vấn đề khác biệt CPU
    Nhưng hóa ra đã có người làm sẵn một tài liệu tổng hợp hoàn hảo cho việc đó. Thật sự rất cảm ơn

  • Trong ví dụ “lấy 0 trừ đi thì sẽ thành số âm”, số âm của 0x123 là 0xfffffedd
    Bài viết nói trình giả lập hiển thị 0xfffffccd, nhưng thực ra 0xfffffedd mới đúng. Tôi đã tự tính lại, và trình giả lập là chính xác

  • Nếu đang tìm một trình giả lập RISC-V tốt thì tôi khuyên dùng RARS