AdaCore / Ada_Drivers_Library

Ada source code and complete sample GNAT projects for selected bare-board platforms supported by GNAT.
BSD 3-Clause "New" or "Revised" License
236 stars 141 forks source link

Access to standard performance counters on RISC-V #362

Closed rod-chapman closed 3 years ago

rod-chapman commented 3 years ago

It would be helpful to offer a standard Ada API to read the values of the standard RISC-V performance counters, specifically the CSRs CYCLE, INSTRET and TIME.

These are always 64-bit unsigned values on both RV32 and RV64, but the implementation differs, since (on RV32) they have to be read as 2 32-bit values and checked for (non-)overflow.

rod-chapman commented 3 years ago

How to organise the source of this package? The package spec is simple, and common to both RV32 and RV64.

The body needs to be implemented in assembler and is different for RV32 and RV64.

What is the best way to organise this and make sure the right version gets compiled, assebled and linked?

rod-chapman commented 3 years ago

Is there a scalar constant defined by the BSP that tells me whether a target is RV32 or RV64 perhaps?

rod-chapman commented 3 years ago

Actually, a static scalar constant (not a string!) would be good so I could write a case statement over its value, and expect the compiler to optimize away the "wrong" branch for any particular target...

Fabien-Chouteau commented 3 years ago

Hi @rod-chapman,

I opened #363 to implement performance CSR on both RV32 and RV64. The API is the same for RV32 or RV64 so you don't have to worry about that in this case.

For the mtime counter the situation is a bit more difficult. mtime is a memory mapped register not a CSR, the reason is to allow mtime to be in a different clock domain than the CPU and therefore keep ticking when the CPU is halted.

Unfortunately the address of mtime is not fixed in the standard, so it can be different for every board.

For the HiFive1 you can use these definitions:

   CLINT_Addr         : constant := 16#02000000#;
   CLINT_Mtime_Offset : constant := 16#BFF8#;

   Mtime_Lo_Addr : Address := To_Address (CLINT_Addr + CLINT_Mtime_Offset);
   Mtime_Hi_Addr : Address := To_Address (CLINT_Addr + CLINT_Mtime_Offset + 4);

   Mtime_Lo : UInt32 with Volatile_Full_Access, Address => Mtime_Lo_Addr;
   Mtime_Hi : UInt32 with Volatile_Full_Access, Address => Mtime_Hi_Addr;