-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Perf counters #388
Merged
Merged
Perf counters #388
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
7a62d60
added counter csr-addresses to constants
jjjt-hub 248ad24
extracted existing counters to new plugin
jjjt-hub 20f638e
removed counter config from demos
jjjt-hub d9d841d
exposed debug-state to other plugins
jjjt-hub 5dd6ff2
exposes privilege information
jjjt-hub cff3bc3
moved timer to CounterPlugin
jjjt-hub 6f57843
added custom counters
jjjt-hub d50a1bc
final touches
jjjt-hub 6d3c518
added Counter to full config
jjjt-hub c06d7f5
renamed utime to time & doc
jjjt-hub 659a8b1
readded legacy counters/timers
jjjt-hub ca82922
added tags to regs to avoid warning when no counters will be generated
jjjt-hub aef4b4a
fixed demo configs
jjjt-hub 9a8cdde
fixed NullPointerException on utimeAccess NONE
jjjt-hub ff2f9ef
fixed cross-phase issue
jjjt-hub 495b6d9
better documentation
jjjt-hub 7882b0f
Revert "removed counter config from demos"
jjjt-hub 02ada2a
Merge branch 'dev' into perf_counters
Dolu1990 7b520aa
fix my bad conflict resolution
Dolu1990 5148bba
fixed broken conditional generation
jjjt-hub File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
package vexriscv.plugin | ||
|
||
import spinal.core._ | ||
|
||
import vexriscv._ | ||
import vexriscv.Riscv.CSR._ | ||
|
||
import scala.collection.mutable._ | ||
|
||
trait CounterService{ | ||
def createEvent(eventId : BigInt) : Unit | ||
def getCondition(eventId : BigInt) : Bool | ||
} | ||
|
||
case class CounterPluginConfig( | ||
NumOfCounters : Byte = 29, | ||
|
||
mcycleAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
ucycleAccess : CsrAccess = CsrAccess.READ_ONLY, | ||
|
||
minstretAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
uinstretAccess : CsrAccess = CsrAccess.READ_ONLY, | ||
|
||
utimeAccess : CsrAccess = CsrAccess.READ_ONLY, | ||
|
||
mcounterenAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
scounterenAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
|
||
mcounterAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
ucounterAccess : CsrAccess = CsrAccess.READ_ONLY, | ||
|
||
// management | ||
meventAccess : CsrAccess = CsrAccess.READ_WRITE, | ||
mcountinhibitAccess : CsrAccess = CsrAccess.READ_WRITE | ||
) { | ||
assert(!ucycleAccess.canWrite) | ||
} | ||
|
||
object Priv{ | ||
val M = 3 | ||
val S = 1 | ||
val U = 0 | ||
} | ||
|
||
class CounterPlugin(config : CounterPluginConfig) extends Plugin[VexRiscv] with CounterService { | ||
import config._ | ||
|
||
def xlen = 32 | ||
|
||
assert(NumOfCounters <= 29, "Cannot create more than 29 custom counters") | ||
assert(NumOfCounters >= 0, "Cannot create less than 0 custom counters") | ||
|
||
// counters : Array[Reg] = null | ||
// event : Array[Reg] = null | ||
|
||
// mcouen : Reg = null | ||
// scouen : Reg = null | ||
|
||
// inhibit : Reg = null | ||
|
||
val eventType : Map[BigInt, Bool] = new HashMap() | ||
|
||
var time : UInt = null | ||
|
||
implicit class PrivilegeHelper(p : PrivilegeService){ | ||
def canMachine() : Bool = p.isMachine() | ||
def canSupervisor() : Bool = p.isMachine() || p.isSupervisor() | ||
} | ||
|
||
implicit class CsrAccessHelper(csrAccess : CsrAccess){ | ||
import CsrAccess._ | ||
import Priv._ | ||
def apply(csrService : CsrInterface, csrAddress : Int, that : Data) : Unit = { | ||
if(csrAccess == `WRITE_ONLY` || csrAccess == `READ_WRITE`) csrService.w(csrAddress, 0, that) | ||
if(csrAccess == `READ_ONLY` || csrAccess == `READ_WRITE`) csrService.r(csrAddress, 0, that) | ||
} | ||
def apply( | ||
csrSrv : CsrInterface, | ||
prvSrv : PrivilegeService, | ||
csrAddress : Int, | ||
that : Data, | ||
privAllows : (Int, Bool)* | ||
) : Unit = { | ||
apply(csrSrv, csrAddress, that) | ||
if(csrAccess != CsrAccess.NONE) csrSrv.during(csrAddress){ | ||
for (ii <- privAllows) { | ||
if (ii._1 == M) | ||
when (~prvSrv.canMachine() || ~ii._2) { csrSrv.forceFailCsr() } | ||
if (ii._1 == S && prvSrv.hasSupervisor()) | ||
when (~prvSrv.canSupervisor() || ~ii._2) { csrSrv.forceFailCsr() } | ||
if (prvSrv.hasUser()) | ||
when (~ii._2) { csrSrv.forceFailCsr() } | ||
} | ||
} | ||
} | ||
} | ||
|
||
override def createEvent(eventId : BigInt) : Unit = { | ||
if (!eventType.contains(eventId)) { | ||
eventType(eventId) = Bool | ||
} | ||
} | ||
|
||
override def getCondition(eventId : BigInt) : Bool = { | ||
eventType(eventId) | ||
} | ||
|
||
override def setup(pipeline : VexRiscv) : Unit = { | ||
import pipeline._ | ||
import pipeline.config._ | ||
|
||
if (utimeAccess != CsrAccess.NONE) time = in UInt(64 bits) setName("utime") | ||
} | ||
|
||
override def build(pipeline : VexRiscv) : Unit = { | ||
import pipeline._ | ||
import pipeline.config._ | ||
|
||
pipeline plug new Area{ | ||
val csrSrv = pipeline.service(classOf[CsrInterface]) | ||
val dbgSrv = pipeline.service(classOf[DebugService]) | ||
val prvSrv = pipeline.service(classOf[PrivilegeService]) | ||
|
||
val dbgCtrEn = ~(dbgSrv.inDebugMode() && dbgSrv.debugState().dcsr.stopcount) | ||
|
||
val menable = RegInit(Bits(3 + NumOfCounters bits).getAllTrue) allowUnsetRegToAvoidLatch | ||
val senable = RegInit(Bits(3 + NumOfCounters bits).getAllTrue) allowUnsetRegToAvoidLatch | ||
val inhibit = Reg(Bits(NumOfCounters bits)) init(0) | ||
val inhibitCY = RegInit(False) | ||
val inhibitIR = RegInit(False) | ||
|
||
val cycle = Reg(UInt(64 bits)) init(0) | ||
cycle := cycle + U(dbgCtrEn && ~inhibitCY) | ||
val instret = Reg(UInt(64 bits)) init(0) | ||
when(pipeline.stages.last.arbitration.isFiring) { | ||
instret := instret + U(dbgCtrEn && ~inhibitIR) | ||
} | ||
|
||
val counter = Array.fill(NumOfCounters){Reg(UInt(64 bits)) init(0)} | ||
val events = Array.fill(NumOfCounters){Reg(UInt(xlen bits)) init(0)} | ||
|
||
var customCounters = new Area { | ||
val increment = Array.fill(NumOfCounters){Bool} | ||
|
||
for (ii <- 0 until NumOfCounters) { | ||
counter(ii) := counter(ii) + U(dbgCtrEn && ~inhibit(ii) && increment(ii)) | ||
|
||
increment(ii) := False | ||
|
||
for (event <- eventType) { | ||
when (event._1 =/= U(0, xlen bits) && event._1 === events(ii)) { | ||
increment(ii) := event._2 | ||
} | ||
} | ||
} | ||
} | ||
|
||
val expose = new Area { | ||
import Priv._ | ||
// inhibit | ||
csrSrv.during(MCOUNTINHIBIT){ when (~prvSrv.isMachine()) {csrSrv.forceFailCsr()} } | ||
csrSrv.rw(MCOUNTINHIBIT, 0 -> inhibitCY, 2 -> inhibitIR, 3 -> inhibit) | ||
|
||
// enable | ||
mcounterenAccess(csrSrv, prvSrv, MCOUNTEREN, menable, S -> False, U -> False) | ||
scounterenAccess(csrSrv, prvSrv, SCOUNTEREN, senable, U -> False) | ||
|
||
// custom counters | ||
for (ii <- 0 until NumOfCounters) { | ||
ucounterAccess(csrSrv, prvSrv, UCOUNTER + ii, counter(ii)(31 downto 0), | ||
S -> menable(3 + ii), | ||
U -> (if (prvSrv.hasSupervisor()) senable(3 + ii) else True), | ||
U -> menable(3 + ii) | ||
) | ||
ucounterAccess(csrSrv, prvSrv, UCOUNTERH + ii, counter(ii)(63 downto 32), | ||
S -> menable(3 + ii), | ||
U -> (if (prvSrv.hasSupervisor()) senable(3 + ii) else True), | ||
U -> menable(3 + ii) | ||
) | ||
|
||
mcounterAccess(csrSrv, prvSrv, MCOUNTER + ii, counter(ii)(31 downto 0), S -> False, U -> False) | ||
mcounterAccess(csrSrv, prvSrv, MCOUNTERH + ii, counter(ii)(63 downto 32), S -> False, U -> False) | ||
meventAccess(csrSrv, prvSrv, MEVENT + ii, events(ii), S -> False, U -> False) | ||
} | ||
|
||
// fixed counters | ||
ucycleAccess(csrSrv, prvSrv, UCYCLE, cycle(31 downto 0), | ||
S -> menable(0), | ||
U -> (if (prvSrv.hasSupervisor()) senable(0) else True), | ||
U -> menable(0) | ||
) | ||
ucycleAccess(csrSrv, prvSrv, UCYCLEH, cycle(63 downto 32), | ||
S -> menable(0), | ||
U -> (if (prvSrv.hasSupervisor()) senable(0) else True), | ||
U -> menable(0) | ||
) | ||
|
||
mcycleAccess(csrSrv, prvSrv, MCYCLE, cycle(31 downto 0), S -> False, U -> False) | ||
mcycleAccess(csrSrv, prvSrv, MCYCLEH, cycle(63 downto 32), S -> False, U -> False) | ||
|
||
if(utimeAccess != CsrAccess.NONE) { | ||
utimeAccess(csrSrv, prvSrv, UTIME, time(31 downto 0), | ||
S -> menable(1), | ||
U -> (if (prvSrv.hasSupervisor()) senable(1) else True), | ||
U -> menable(1) | ||
) | ||
utimeAccess(csrSrv, prvSrv, UTIMEH, time(63 downto 32), | ||
S -> menable(1), | ||
U -> (if (prvSrv.hasSupervisor()) senable(1) else True), | ||
U -> menable(1) | ||
) | ||
} | ||
|
||
uinstretAccess(csrSrv, prvSrv, UINSTRET, instret(31 downto 0), | ||
S -> menable(2), | ||
U -> (if (prvSrv.hasSupervisor()) senable(2) else True), | ||
U -> menable(2) | ||
) | ||
uinstretAccess(csrSrv, prvSrv, UINSTRETH, instret(63 downto 32), | ||
S -> menable(2), | ||
U -> (if (prvSrv.hasSupervisor()) senable(2) else True), | ||
U -> menable(2) | ||
) | ||
|
||
minstretAccess(csrSrv, prvSrv, MINSTRET, instret(31 downto 0), S -> False, U -> False) | ||
minstretAccess(csrSrv, prvSrv, MINSTRETH, instret(63 downto 32), S -> False, U -> False) | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, would need to preserve that feature in the CsrPlugin. (even if that is a duplication) to not break people code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The feature is still in CSRPlugin, even if disabled when CounterService is present (which in this demo it is), so it should break no existing code which uses the Counters in CsrPlugin.