
محاكي مجموعة تعليمات RISC-V وظيفي يدعم امتدادات متعددة (RV32/64، V، التشفير) مع وضع تصحيح تفاعلي، وتكامل GDB، ونمذجة على مستوى التعليمات للتطوير المشترك بين العتاد والبرمجيات واستكشاف المعمارية.
Spike، محاكي مجموعة تعليمات RISC-V، ينفذ نموذجًا وظيفيًا لواحد أو أكثر من أنوية RISC-V. تمت تسميته على اسم المسمار الذهبي المستخدم للاحتفال بإكتمال السكك الحديدية العابرة للقارات في الولايات المتحدة.
يدعم Spike ميزات RISC-V ISA التالية:
يتم إصدار الإصدارات بشكل أساسي للإشارة إلى وقت توسيع واجهة البرمجة أو جعلها غير متوافقة. وبهذا المعنى، يهدف Spike إلى اتباع مخطط إصدار SemVer، حيث يتم زيادة أرقام الإصدارات الرئيسية عند إجراء تغييرات غير متوافقة مع الإصدارات السابقة في واجهة البرمجة؛ ويتم زيادة أرقام الإصدارات الثانوية عند إضافة واجهات برمجة جديدة؛ ويتم زيادة أرقام إصدارات التصحيح عند إصلاح الأخطاء بطريقة متوافقة مع الإصدارات السابقة.
واجهة البرمجة العامة الرئيسية لـ Spike هي مجموعة تعليمات RISC-V. واجهة C++ للأجزاء الداخلية لـ Spike لا تعتبر واجهة برمجة عامة في هذا الوقت، وسيتم إجراء تغييرات غير متوافقة مع الإصدارات السابقة على هذه الواجهة دون زيادة رقم الإصدار الرئيسي.
نفترض أن متغير البيئة RISCV مضبوط على مسار تثبيت أدوات RISC-V.
$ apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ make
$ [sudo] make install
إذا كان نظامك يستخدم مدير الحزم yum، فيمكنك استبدال yum install dtc للخطوة الأولى.
قم بتثبيت bash و gmake و dtc واستخدم clang.
$ pkg_add bash gmake dtc
$ exec bash
$ export CC=cc; export CXX=c++
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ gmake
$ [doas] make install
قم بتثبيت spike (انظر خطوات البناء)، riscv-gnu-toolchain، و riscv-pk.
اكتب برنامج C قصيرًا وسمِّه hello.c. ثم قم بتجميعه إلى ملف ثنائي RISC-V ELF باسم hello:
$ riscv64-unknown-elf-gcc -o hello hello.c
الآن يمكنك محاكاة البرنامج فوق نواة الوكيل:
$ spike pk hello
تتطلب إضافة تعليمة إلى المحاكي خطوتين:
وصف السلوك الوظيفي للتعليمة في الملف riscv/insns/<new_instruction_name>.h. افحص التعليمات الأخرى في نفس الدليل كنقطة انطلاق.
إضافة كود العملية وقناع كود العملية إلى riscv/opcodes.h. بدلاً من ذلك، أضفها إلى حزمة riscv-opcodes، وسيقوم بذلك نيابة عنك:
$ cd ../riscv-opcodes
$ vi opcodes // أضف سطرًا للتعليمة الجديدة
$ make install
أضف التعليمة إلى riscv/riscv.mk.in. وإلا، لن يتم تضمين التعليمة في البناء وستُعامل كتعليمة غير قانونية.
أعد بناء المحاكي.
لاستدعاء وضع التصحيح التفاعلي، قم بتشغيل spike مع -d:
$ spike -d pk hello
لعرض محتويات سجل عدد صحيح (0 للنواة 0):
: reg 0 a0
لعرض محتويات سجل فاصلة عائمة:
: fregs 0 ft0
أو:
: fregd 0 ft0
اعتمادًا على ما إذا كنت ترغب في طباعة السجل بدقة مفردة أو مزدوجة.
لعرض محتويات موقع ذاكرة (عنوان فعلي بالنظام الست عشري):
: mem 2020
لعرض محتويات الذاكرة بعنوان افتراضي (0 للنواة 0):
: mem 0 2020
يمكنك التقدم بتعليمة واحدة بالضغط على مفتاح Enter. يمكنك أيضًا التنفيذ حتى يتم الوصول إلى مساواة مرغوبة:
: until pc 0 2020 (توقف عندما pc=2020)
: until reg 0 mie a (توقف عندما يكون السجل mie=0xa)
: until mem 2020 50a9907311096993 (توقف عندما mem[2020]=50a9907311096993)
بدلاً من ذلك، يمكنك التنفيذ طالما أن المساواة صحيحة:
: while mem 2020 50a9907311096993
يمكنك متابعة التنفيذ إلى أجل غير مسمى عن طريق:
: r
في أي نقطة أثناء التنفيذ (حتى بدون -d)، يمكنك الدخول إلى وضع التصحيح التفاعلي باستخدام <control>-<c>.
لإنهاء المحاكاة من موجه التصحيح، اضغط <control>-<c> أو:
: q
بديل لوضع التصحيح التفاعلي هو الاتصال باستخدام gdb. نظرًا لأن spike يحاول أن يكون مثل الأجهزة الحقيقية، فأنت تحتاج أيضًا إلى OpenOCD للقيام بذلك. سنستخدم برنامج الاختبار التالي:
$ cat rot13.c
#include <stdio.h>
char text[] = "Vafgehpgvba frgf jnag gb or serr!";
// لا تستخدم المكدس، لأن sp ليس مضبوطًا.
volatile int wait = 1;
int main()
{
int i = 0;
while (text[i]) {
char lower = text[i] | 32;
if (lower >= 'a' && lower <= 'm')
text[i] += 13;
else if (lower > 'm' && lower <= 'z')
text[i] -= 13;
i++;
}
done:
printf("decoded text: %s\n", text);
}
$ riscv64-unknown-elf-gcc -g -Og --specs=semihost.specs -o rot13 rot13.c
لتصحيح هذا البرنامج، قم أولاً بتشغيل spike مع إخباره بالاستماع لـ OpenOCD:
$ spike --rbb-port=9824 -m0x10000:0x20000 rot13
Listening for remote bitbang connection on port 9824.
...
في قذيفة منفصلة، قم بتشغيل OpenOCD مع ملف التكوين المناسب:
$ cat spike.cfg
adapter driver remote_bitbang
remote_bitbang host localhost
remote_bitbang port 9824
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0xdeadbeef
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
gdb report_data_abort enable
init
arm semihosting enable
halt
$ openocd -f spike.cfg
Open On-Chip Debugger 0.12.0
...
Info : starting gdb server for riscv.cpu on 3333
Info : Listening on port 3333 for gdb connections
riscv.cpu halted due to debug-request. Semihosting is active.
...
riscv.cpu: target state: halted
في قذيفة أخرى، ابدأ جلسة التصحيح gdb:
$ riscv64-unknown-elf-gdb rot13
...
Reading symbols from rot13...
(gdb) target extended-remote localhost:3333
...
(gdb) load
...
(gdb) set $sp=0x2fff0
(gdb) b main
Breakpoint 1 at 0x10202: file rot13.c, line 5.
(gdb) c
Continuing.
Disabling abstract command writes to CSRs.
Breakpoint 1, main () at rot13.c:5
5 {
(gdb) print text
$1 = "Vafgehpgvba frgf jnag gb or serr!"
(gdb) until done
[riscv.cpu] Found 4 triggers
main () at rot13.c:16
16 printf("decoded text: %s\n", text);
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00019ff8 in _exit ()
(gdb)
...
على طرفية OpenOCD سترى:
...
decoded text: Instruction sets want to be free!
semihosting: *** application exited with 0 ***
riscv.cpu halted due to breakpoint. Semihosting is active.