FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-V SpikeシミュレータでC/C++のprintfを実現する仕組み (6. ファイルシステムの呼び出し)

Hello Worldのプログラムを動かしながら、RISC-V Spikeシミュレータのログを追っていき、RISC-Vのブートシーケンスを追っていく、その3。

Spikeシミュレータはファイルの呼び出しもできる。これを実現しているのは、Spikeとは外部に接続されているpk(Proxy Kernel)だ。

試しにこんなプログラムを書いてRISC-VのGCCコンパイルしてみる。

#include <stdio.h>
#include <stdlib.h>

int main ()
{
  printf("Hello World\n");

  FILE *fp;
  if ((fp = fopen("sample_hello.txt", "w")) == NULL) {
    perror ("sample_hello.txt");
    exit(EXIT_FAILURE);
  }
  fprintf (fp, "Hello World\n");
  fclose (fp);

  if ((fp = fopen("sample_hello.txt", "r")) == NULL) {
    perror ("sample_hello.txt");
    exit(EXIT_FAILURE);
  }
  char cin[100];
  fscanf (fp, "%s", cin);
  printf ("%s\n", cin);

  char c[100];
  scanf("%s", c);
  printf("%s\n", c);

  return 0;
}
run: file_access_riscv file_access_x86
    spike pk $<

file_access_riscv: file_access.c
    riscv64-unknown-elf-gcc $^ -o $@

file_access_x86: file_access.c
    gcc $^ -o $@

これで実行してみると、通常のprintf/scanfはProxy Kernelの力で問題なく読み取りができる。一方で、ファイルシステムのほうは少し工夫が必要だった。 上記のプログラムでsample_hello.txtが存在しない場合、エラーとなって終了してしまう。

$ make run
spike pk file_access_riscv
Hello World
sample_hello.txt: No such file or directory
Makefile:2: recipe for target 'run' failed
make: *** [run] Error 1

ファイルをあらかじめ作っておくと、問題なく動作する。これはpkのバグか?仕様か?

$ make run

spike pk file_access_riscv
Hello World
Hello
hello
hello
$ cat sample_hello.txt
Hello World
f:id:msyksphinz:20180724020800p:plain

というわけで、動作の様子を観測したいので自作ISSで関数トレースを出してみたのだが、良くわからなくなった... もう少し解析だな。

...
          <Return: plic_prop>
          <FunctionCall 46805 plic_done(0x800035d4)>
          <Return: plic_done>
        <Return: fdt_scan_helper>
      <Return: fdt_scan_helper>
    <Return: fdt_scan>
  <Return: query_plic>
  <FunctionCall 46988 hart_plic_init(0x80002918)>
  <Return: hart_plic_init>
  <FunctionCall 47025 file_init(0x80000696)>
    <FunctionCall 47032 file_get_free(0x800005b0)>
    <Return: file_get_free>
    <FunctionCall 47053 file_dup(0x8000064a)>
      <FunctionCall 47068 file_incref(0x800005f0)>
      <Return: file_incref>
    <Return: file_dup>
    <FunctionCall 47082 file_get_free(0x800005b0)>
    <Return: file_get_free>
    <FunctionCall 47108 file_dup(0x8000064a)>
      <FunctionCall 47130 file_incref(0x800005f0)>
      <Return: file_incref>
    <Return: file_dup>
    <FunctionCall 47144 file_get_free(0x800005b0)>
    <Return: file_get_free>
    <FunctionCall 47175 file_dup(0x8000064a)>
      <FunctionCall 47204 file_incref(0x800005f0)>
      <Return: file_incref>
    <Return: file_dup>
  <Return: file_init>
  <FunctionCall 47223 pk_vm_init(0x80001732)>
    <FunctionCall 47257 __page_alloc(0x80000e34)>
      <FunctionCall 47278 memset(0x80007912)>
      <Return: memset>
    <Return: __page_alloc>
    <FunctionCall 48841 __map_kernel_range(0x8000163c)>
      <FunctionCall 48877 __walk_internal(0x80000e86)>
        <FunctionCall 48897 __page_alloc(0x80000e34)>
          <FunctionCall 48918 memset(0x80007912)>
          <Return: memset>
        <Return: __page_alloc>