Skip to content

Commit 4b71c79

Browse files
committed
Refactor the performance counters code so that the operation of
reading a performance counter is separate and orthogonal to the CSRRW, CSRRS, and CSRRC instructions. This cuts down on the code needed, since the CSRRW, CSRRS, and CSRRC instructions operate the same for all CSR registers, and the RevRegFile handles CSRs with special meanings.
1 parent 45cbad0 commit 4b71c79

File tree

2 files changed

+66
-76
lines changed

2 files changed

+66
-76
lines changed

include/RevRegFile.h

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,6 @@ class RevRegFile {
209209
/// Invoke the MarkLoadComplete function
210210
void MarkLoadComplete( const MemReq& req ) const { MarkLoadCompleteFunc( req ); }
211211

212-
/// Get the number of instructions retired
213-
uint64_t GetInstRet() const { return InstRet; }
214-
215212
/// Capture the PC of current instruction which raised exception
216213
void SetSEPC() {
217214
if( IsRV32 ) {
@@ -338,16 +335,70 @@ class RevRegFile {
338335
}
339336
}
340337

338+
private:
339+
// Performance counters
340+
341+
// Template is used to break circular dependencies between RevCore and RevRegFile
342+
template<typename CORE>
343+
uint64_t rdcycle( CORE* core ) const {
344+
return core->GetCycles();
345+
}
346+
347+
template<typename CORE>
348+
uint64_t rdtime( CORE* core ) const {
349+
return core->GetCurrentSimCycle();
350+
}
351+
352+
template<typename CORE>
353+
uint64_t rdinstret( CORE* ) const {
354+
return InstRet;
355+
}
356+
357+
enum class Half { Lo, Hi };
358+
359+
/// Performance Counter template
360+
// Passed a function which gets the 64-bit value of a performance counter
361+
template<typename T, Half HALF, uint64_t ( RevRegFile::*COUNTER )( RevCore* ) const>
362+
T GetPerfCounter() const {
363+
if constexpr( sizeof( T ) == sizeof( uint32_t ) ) {
364+
// clang-format off
365+
if constexpr( HALF == Half::Lo ) {
366+
return static_cast<T>( ( this->*COUNTER )( Core ) & 0xffffffff );
367+
} else {
368+
return static_cast<T>( ( this->*COUNTER )( Core ) >> 32 );
369+
}
370+
// clang-format on
371+
} else {
372+
if constexpr( HALF == Half::Lo ) {
373+
return ( this->*COUNTER )( Core );
374+
} else {
375+
return 0; // Hi half is not available on RV64
376+
}
377+
}
378+
}
379+
380+
public:
341381
/// Get a CSR register
342382
template<typename T>
343383
T GetCSR( size_t csr ) const {
344-
// We store fcsr separately from the global CSR
384+
// clang-format off
345385
switch( csr ) {
346-
case 1: return static_cast<uint32_t>( fcsr ) >> 0 & 0b00011111u; break;
347-
case 2: return static_cast<uint32_t>( fcsr ) >> 5 & 0b00000111u; break;
348-
case 3: return static_cast<uint32_t>( fcsr ) >> 0 & 0b11111111u; break;
349386
default: return static_cast<T>( CSR[csr] );
387+
388+
// We store fcsr separately from the global CSR
389+
case 1: return static_cast<uint32_t>( fcsr ) >> 0 & 0b00011111u;
390+
case 2: return static_cast<uint32_t>( fcsr ) >> 5 & 0b00000111u;
391+
case 3: return static_cast<uint32_t>( fcsr ) >> 0 & 0b11111111u;
392+
393+
// Performance Counters
394+
case 0xc00: return GetPerfCounter<T, Half::Lo, &RevRegFile::rdcycle>();
395+
case 0xc80: return GetPerfCounter<T, Half::Hi, &RevRegFile::rdcycle>();
396+
case 0xc01: return GetPerfCounter<T, Half::Lo, &RevRegFile::rdtime>();
397+
case 0xc81: return GetPerfCounter<T, Half::Hi, &RevRegFile::rdtime>();
398+
case 0xc02: return GetPerfCounter<T, Half::Lo, &RevRegFile::rdinstret>();
399+
case 0xc82: return GetPerfCounter<T, Half::Hi, &RevRegFile::rdinstret>();
350400
}
401+
// clang-format on
351402
}
352403

353404
/// Set a CSR register

include/insns/Zicsr.h

Lines changed: 8 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,7 @@ class Zicsr : public RevExt {
2323
/// Modify a CSR Register according to CSRRW, CSRRS, or CSRRC
2424
// Because CSR has a 32/64-bit width, this function is templatized
2525
template<typename XLEN, OpKind OPKIND, CSROp OP>
26-
static bool ModCSRImpl( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
27-
28-
// Alternative forms of rdcycle[h], rdtime[h], rdinstret[h] which use an immediate 0 or csrrc
29-
// Canonical forms of rdcycle[h], rdtime[h], rdinstret[h] use csrrs with register x0
30-
if( OP != CSROp::Write && Inst.rs1 == 0 ) {
31-
switch( Inst.imm ) {
32-
case 0xc00: return rdcycle( F, R, M, Inst );
33-
case 0xc80: return rdcycleh( F, R, M, Inst );
34-
case 0xc01: return rdtime( F, R, M, Inst );
35-
case 0xc81: return rdtimeh( F, R, M, Inst );
36-
case 0xc02: return rdinstret( F, R, M, Inst );
37-
case 0xc82: return rdinstreth( F, R, M, Inst );
38-
}
39-
}
40-
26+
static bool ModCSRImpl( RevRegFile* R, const RevInst& Inst ) {
4127
XLEN old = 0;
4228

4329
// CSRRW with rd == zero does not read CSR
@@ -81,7 +67,7 @@ class Zicsr : public RevExt {
8167
// This calls the 32/64-bit ModCSR depending on the current XLEN
8268
template<OpKind OPKIND, CSROp OP>
8369
static bool ModCSR( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
84-
return R->IsRV32 ? ModCSRImpl<uint32_t, OPKIND, OP>( F, R, M, Inst ) : ModCSRImpl<uint64_t, OPKIND, OP>( F, R, M, Inst );
70+
return R->IsRV32 ? ModCSRImpl<uint32_t, OPKIND, OP>( R, Inst ) : ModCSRImpl<uint64_t, OPKIND, OP>( R, Inst );
8571
}
8672

8773
static constexpr auto& csrrw = ModCSR<OpKind::Reg, CSROp::Write>;
@@ -91,53 +77,6 @@ class Zicsr : public RevExt {
9177
static constexpr auto& csrrsi = ModCSR<OpKind::Imm, CSROp::Set>;
9278
static constexpr auto& csrrci = ModCSR<OpKind::Imm, CSROp::Clear>;
9379

94-
// Performance counters
95-
// TODO: These should be moved to a separate Zicntr extension, but right now the
96-
// spec is unclear on what order Zicntr should appear in an architecture string
97-
98-
// template is used to break circular dependencies and allow for an incomplete RevCore type now
99-
template<typename T, typename = std::enable_if_t<std::is_same_v<T, RevRegFile>>>
100-
static uint64_t rdcycleImpl( RevFeature* F, T* R, RevMem* M, const RevInst& Inst ) {
101-
return R->Core->GetCycles();
102-
}
103-
104-
template<typename T, typename = std::enable_if_t<std::is_same_v<T, RevRegFile>>>
105-
static uint64_t rdtimeImpl( RevFeature* F, T* R, RevMem* M, const RevInst& Inst ) {
106-
return R->Core->GetCurrentSimCycle();
107-
}
108-
109-
static uint64_t rdinstretImpl( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) { return R->GetInstRet(); }
110-
111-
enum Half { Lo, Hi };
112-
113-
/// Performance Counter template
114-
// Passed a function which gets the 64-bit value of a performance counter
115-
template<Half HALF, uint64_t COUNTER( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst )>
116-
static bool perfCounter( RevFeature* F, RevRegFile* R, RevMem* M, const RevInst& Inst ) {
117-
if( R->IsRV32 ) {
118-
if constexpr( HALF == Lo ) {
119-
R->SetX( Inst.rd, static_cast<uint32_t>( COUNTER( F, R, M, Inst ) & 0xffffffff ) );
120-
} else {
121-
R->SetX( Inst.rd, static_cast<uint32_t>( COUNTER( F, R, M, Inst ) >> 32 ) );
122-
}
123-
} else {
124-
if constexpr( HALF == Lo ) {
125-
R->SetX( Inst.rd, COUNTER( F, R, M, Inst ) );
126-
} else {
127-
return false; // Hi half is not available on RV64
128-
}
129-
}
130-
R->AdvancePC( Inst );
131-
return true;
132-
}
133-
134-
static constexpr auto& rdcycle = perfCounter<Lo, rdcycleImpl>;
135-
static constexpr auto& rdcycleh = perfCounter<Hi, rdcycleImpl>;
136-
static constexpr auto& rdtime = perfCounter<Lo, rdtimeImpl>;
137-
static constexpr auto& rdtimeh = perfCounter<Hi, rdtimeImpl>;
138-
static constexpr auto& rdinstret = perfCounter<Lo, rdinstretImpl>;
139-
static constexpr auto& rdinstreth = perfCounter<Hi, rdinstretImpl>;
140-
14180
// ----------------------------------------------------------------------
14281
//
14382
// RISC-V CSR Instructions
@@ -178,12 +117,12 @@ class Zicsr : public RevExt {
178117
{ RevZicsrInstDefaults().SetMnemonic( "csrrci %rd, %csr, $imm" ).SetFunct3( 0b111 ).SetImplFunc( csrrci ).SetPredicate( []( uint32_t Inst ){ return DECODE_RD( Inst ) != 0; } ) },
179118
{ RevZicsrInstDefaults().SetMnemonic( "csrci %csr, $imm" ).SetFunct3( 0b111 ).SetImplFunc( csrrci ).SetPredicate( []( uint32_t Inst ){ return DECODE_RD( Inst ) == 0; } ) },
180119

181-
{ RevZicsrInstDefaults().SetMnemonic( "rdcycle %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdcycle ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc00; } ) },
182-
{ RevZicsrInstDefaults().SetMnemonic( "rdcycleh %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdcycleh ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc80; } ) },
183-
{ RevZicsrInstDefaults().SetMnemonic( "rdtime %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdtime ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc01; } ) },
184-
{ RevZicsrInstDefaults().SetMnemonic( "rdtimeh %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdtimeh ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc81; } ) },
185-
{ RevZicsrInstDefaults().SetMnemonic( "rdinstret %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdinstret ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc02; } ) },
186-
{ RevZicsrInstDefaults().SetMnemonic( "rdinstreth %rd" ).SetFunct3( 0b010 ).SetImplFunc( rdinstreth ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc82; } ) },
120+
{ RevZicsrInstDefaults().SetMnemonic( "rdcycle %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc00; } ) },
121+
{ RevZicsrInstDefaults().SetMnemonic( "rdcycleh %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc80; } ) },
122+
{ RevZicsrInstDefaults().SetMnemonic( "rdtime %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc01; } ) },
123+
{ RevZicsrInstDefaults().SetMnemonic( "rdtimeh %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc81; } ) },
124+
{ RevZicsrInstDefaults().SetMnemonic( "rdinstret %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc02; } ) },
125+
{ RevZicsrInstDefaults().SetMnemonic( "rdinstreth %rd" ).SetFunct3( 0b010 ).SetImplFunc( csrrs ).SetPredicate( []( uint32_t Inst ){ return DECODE_RS1( Inst ) == 0 && DECODE_IMM12( Inst ) == 0xc82; } ) },
187126
};
188127
// clang-format on
189128

0 commit comments

Comments
 (0)