Reading files in software workload

110 views
Skip to first unread message

Siyi Hu

unread,
May 4, 2020, 4:56:07 AM5/4/20
to Chipyard
Hi all,

We need to load data from a file when running software workload (baremetal version currently) to test the generated verilog on Verilator.

However, it seems that neither open nor fopen, and other file operating syscalls/functions, are implemented in current riscv toolchain. 
I also checked the examples, SHA3 and Gemmini, and it looks like they just hardcoded the data into the programs.

So my question is that, is it possible to read a file in baremetal software workload?

Any help would be appreciated.

Best regards,
Siyi

Tynan McAuley

unread,
May 4, 2020, 12:06:33 PM5/4/20
to Chipyard
I typically get around this problem using objcopy, following a strategy like this one: https://balau82.wordpress.com/2012/02/19/linking-a-binary-blob-with-gcc/

This way, the file you want to read is compiled into your ELF. Is something like that what you had in mind?

-Tynan

Cheng Lei

unread,
May 4, 2020, 12:10:52 PM5/4/20
to Chipyard
I think we can use libgloss for this purpose (there are examples under /chipyard/tests/). However, I did not make this approach work for me.
Instead I started from the sha3 example, and added the following function calls to the syscalls.c file, and I am able to use them for my baremetal program.

static uintptr_t syscall6(uintptr_t which, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4)
{
 
volatile uint64_t magic_mem[8] __attribute__((aligned(64)));
  magic_mem
[0] = which;
  magic_mem
[1] = arg0;
  magic_mem
[2] = arg1;
  magic_mem
[3] = arg2;
  magic_mem
[4] = arg3;
  magic_mem
[5] = arg4;
  __sync_synchronize
();


  tohost
= (uintptr_t)magic_mem;
 
while (fromhost == 0)
   
;
  fromhost
= 0;


  __sync_synchronize
();
 
return magic_mem[0];
}
int  open(  char  *filename,  int  access,  int  permission  )
{
 
int ret = syscall6(SYS_open, AT_FDCWD, (uintptr_t)filename, strlen(filename), access, permission);
 
return ret;
}
int  read(  int  handle,  void  *buffer,  int  nbyte )
{
 
int ret = syscall(SYS_read, handle, (uintptr_t)buffer, nbyte);
 
return ret;
}
int  write(  int  handle,  void  *buffer,  int  nbyte  )
{
 
int ret = syscall(SYS_write, handle, (uintptr_t)buffer, nbyte);
 
return ret;
}
int  close(  int  handle  )
{
 
int ret = syscall(SYS_close, handle, 0, 0);
 
return ret;
}




The related MACRO definitions and function declarations are as followings:

#define O_RDONLY 0x0000
#define O_WRONLY 0x0001
#define O_RDWR 0x0002
#define O_ACCMODE 0x0003
//#define O_CREAT         0x0100
#define O_CREAT 0x0200
#define S_IRWXU 0000700


extern int  open(  char  *filename,  int  access,  int  permission  );
extern int  read(  int  handle,  void  *buffer,  int  nbyte );
extern int  write(  int  handle,  void  *buffer,  int  nbyte  );
extern int  close(  int  handle  );

Siyi Hu

unread,
May 5, 2020, 8:41:38 AM5/5/20
to Chipyard
Hi Tynan,

Thanks so much for your advice. 

I didn't realize I could use objcopy to directly compile the file data into the ELF.
This does make sense and I'll give it a try later.

With best regards,
Siyi

2020年5月5日火曜日 1時06分33秒 UTC+9 Tynan McAuley:

Siyi Hu

unread,
May 5, 2020, 9:13:36 AM5/5/20
to Chipyard
Hi Lei,

Thank you very much for your help. This approach is elegant.
Actually I've also been checking Linux kernel source these days in order to try adding open/write syscalls by myself.

After adding your code snippets into syscalls.c, I managed to compile the baremetal ELF eventually.

However, when I try to run the program to test my circuit, I got the following runtime error:

./simulator-chipyard-Sha3RocketConfig-debug ../../tests/sha3/bare/sha3-rocc.riscv
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 43881
[UART] UART0 is here (stdin/stdout).
terminate called after throwing an instance of 'std::runtime_error'
  what():  bad syscall #1024

I directly included the header file ~/chipyard_1.2.0/riscv-tools-install/riscv64-unknown-elf/include/syscall.h in syscalls.c, and it seems that SYS_open is defined like this:
......
#define OLD_SYSCALL_THRESHOLD 1024
#define SYS_open 1024
......

I've also tried to define SYS_open to 5 (which is adopted by Linux) and got the same runtime error as above.

So I'm wondering which syscall number should I pick up in this system to let it work correctly?

Besides, did you also implement open/write/close functions by yourself or it has already existed in current riscv-toolchains?

With best regards,
Siyi

2020年5月5日火曜日 1時10分52秒 UTC+9 Cheng Lei:

Cheng Lei

unread,
May 5, 2020, 12:59:31 PM5/5/20
to Chipyard
Hi Siyi,
Actually, I was using Gemmini examples, not Sha3. I am sorry for the mistake. And the version of the Chipyard I am working on is 1.1. 
Please try the Gemmini baremetal tests.
I also forgot to provide you the following definitions


#define AT_FDCWD -100
#define SYS_write 64
#define SYS_read  63
#define SYS_open  56
#define SYS_close 57


The syscalls are implemented in Fesvr already.
I suggest you take a look at the file /esp-tools/riscv-is-sim/fesvr/syscall.cc, the above syscall numbers were taken from this file.

The file we are working on is in our local machine. When RISC-V issues an file operation, the command is passed to the local machine through HTIF interface. The front end server receives the command and performs the file operations for us, and sends the results back.

When I compiled my program, I used all the options from the gemmini examples. 

riscv64-unknown-elf-gcc  -DPREALLOCATE=1 -DMULTITHREAD=1 -mcmodel=medany -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf -march=rv64gc -Wa,-march=rv64gcxhwacha -lm -lgcc -I/home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests -I/home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests/env -I/home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/.. -I/home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests/benchmarks/common -DID_STRING=  -nostdlib -nostartfiles -static -T /home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests/benchmarks/common/test.ld -DBAREMETAL=1  /home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../bareMetalC/aligned.c  -o aligned-baremetal \
 
/home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests/benchmarks/common/syscalls.c /home/lei/work/chipyard1.1/chipyard/generators/gemmini/software/gemmini-rocc-tests/build/../riscv-tests/benchmarks/common/crt.S



Siyi Hu

unread,
May 7, 2020, 8:27:26 PM5/7/20
to Chipyard
Hi Cheng,

I finally got these system calls worked fine thanks to your helps. Much appreciated!

Although, I also found a weird thing. I have to append a exclamation mark at the end of the file name or the open system call will fail. (E.g., if I need to open /data/cnr-2000, then I need to generate a file named /data/cnr-2000!)
Maybe something in my environment went wrong, but not a problem. :)

With best regards,
Siyi

2020年5月6日水曜日 1時59分31秒 UTC+9 Cheng Lei:

Cheng Lei

unread,
May 7, 2020, 9:32:50 PM5/7/20
to Chipyard
Good to know you got it working. For the filename problem, I guess we should not use uintptr_t conversion in the open function, probably we should just use uint64_t. I am not sure about it.
Reply all
Reply to author
Forward
0 new messages