From eae4fe1469e22e467d286a79850041363750d452 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 29 Jun 2017 19:09:57 -0700 Subject: [PATCH 01/11] plic: Recode to use the knowledge that only one interrupt can be claimed at a time. --- src/main/scala/uncore/devices/Plic.scala | 29 ++++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index a71b7d5c..96451a08 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -147,13 +147,7 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule else Wire(init=Vec.fill(nHarts)(UInt(0))) val pending = Reg(init=Vec.fill(nDevices+1){Bool(false)}) val enables = Reg(Vec(nHarts, Vec(nDevices+1, Bool()))) - - for ((p, g) <- pending zip gateways) { - g.ready := !p - g.complete := false - when (g.valid) { p := true } - } - + def findMax(x: Seq[UInt]): (UInt, UInt) = { if (x.length > 1) { val half = 1 << (log2Ceil(x.length) - 1) @@ -182,14 +176,28 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) } + val claimer = Wire(init = Vec.fill(nHarts){Bool(false)}) + val claiming = Wire(init = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i)), UInt(0, width=log2Up(nDevices+1)))}) + val claimedDevs = Wire(init = Vec(claiming.reduceLeft( _ | _ ).toBools)) + + for ((pg, c) <- (pending zip gateways) zip claimedDevs) { + val p = pg._1 + val g = pg._2 + g.ready := !p + g.complete := false + when(c) { + p := false + }.elsewhen (g.valid) { + p := true + } + } + val hartRegFields = Seq.tabulate(nHarts) { i => PLICConsts.hartBase(i) -> Seq( priorityRegField(threshold(i)), RegField(32, RegReadFn { valid => - when (valid) { - pending(maxDevs(i)) := Bool(false) - } + claimer(i) := valid (Bool(true), maxDevs(i)) }, RegWriteFn { (valid, data) => @@ -203,6 +211,7 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule ) } + node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*) priority(0) := 0 From 834bcf6b7e195be730aef74a78ffad3f8f30b397 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 29 Jun 2017 19:35:15 -0700 Subject: [PATCH 02/11] PLIC: simplify some scala code --- src/main/scala/uncore/devices/Plic.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 96451a08..e2d31927 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -177,12 +177,10 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule } val claimer = Wire(init = Vec.fill(nHarts){Bool(false)}) - val claiming = Wire(init = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i)), UInt(0, width=log2Up(nDevices+1)))}) + val claiming = Wire(init = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i)), UInt(0))}) val claimedDevs = Wire(init = Vec(claiming.reduceLeft( _ | _ ).toBools)) - for ((pg, c) <- (pending zip gateways) zip claimedDevs) { - val p = pg._1 - val g = pg._2 + for ((p, g), c) <- (pending zip gateways) zip claimedDevs) { g.ready := !p g.complete := false when(c) { From e43b7accf9882ee2279276b7e3142f46444704f8 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 30 Jun 2017 01:06:02 -0700 Subject: [PATCH 03/11] Fix compile error and eliminate wasteful wires --- src/main/scala/uncore/devices/Plic.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index e2d31927..06be534e 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -176,11 +176,11 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) } - val claimer = Wire(init = Vec.fill(nHarts){Bool(false)}) - val claiming = Wire(init = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i)), UInt(0))}) - val claimedDevs = Wire(init = Vec(claiming.reduceLeft( _ | _ ).toBools)) + val claimer = Wire(Vec(nHarts, Bool())) + val claiming = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i), nDevices+1), UInt(0))} + val claimedDevs = Vec(claiming.reduceLeft( _ | _ ).toBools) - for ((p, g), c) <- (pending zip gateways) zip claimedDevs) { + (pending zip gateways) zip claimedDevs) foreach { case ((p, g), c) => g.ready := !p g.complete := false when(c) { From 3dca2bc4a3d3cb7bad11d519f0ed5f3f8400793d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 30 Jun 2017 01:07:29 -0700 Subject: [PATCH 04/11] gah --- src/main/scala/uncore/devices/Plic.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 06be534e..25009e60 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -180,7 +180,7 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule val claiming = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i), nDevices+1), UInt(0))} val claimedDevs = Vec(claiming.reduceLeft( _ | _ ).toBools) - (pending zip gateways) zip claimedDevs) foreach { case ((p, g), c) => + ((pending zip gateways) zip claimedDevs) foreach { case ((p, g), c) => g.ready := !p g.complete := false when(c) { From e8e709c941176462748840a9dd76741beb763177 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 30 Jun 2017 08:36:00 -0700 Subject: [PATCH 05/11] plic: Use same recoding technique on complete as well as claim --- src/main/scala/uncore/devices/Plic.scala | 32 +++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 25009e60..2f73bdaa 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -176,18 +176,33 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) } + // When a hart reads its claim/complete register, then the + // device which is currently its highest priority is no longer pending. + // This code expolits the fact that only one hart can claim a device at + // a time through the TL interface. + // Note: PLIC doesn't care which hart reads the register. val claimer = Wire(Vec(nHarts, Bool())) val claiming = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i), nDevices+1), UInt(0))} val claimedDevs = Vec(claiming.reduceLeft( _ | _ ).toBools) ((pending zip gateways) zip claimedDevs) foreach { case ((p, g), c) => g.ready := !p - g.complete := false - when(c) { - p := false - }.elsewhen (g.valid) { - p := true - } + when (c || g.valid) { p := !c } + } + + // When a hart writes a claim/complete register, then + // the written device (as long as it is actually enabled for that + // hart) is marked complete. + // This code expolits the fact that only one hart can complete a device at + // a time through the TL interface + // (Note -- PLIC doesn't care which hart writes the register) + val completer = Wire(Vec(nHarts, Bool())) + val completingDevs = Wire(Vec(nHarts, UInt(width = log2Up(pending.size)))) + val completing = Vec.tabulate(nHarts){i => Mux(completer(i), UIntToOH(completingDevs(i), nDevices+1), UInt(0))} + val completedDevs = Vec(completing.reduceLeft( _ | _ ).toBools) + + (gateways zip completedDevs) foreach { case (g, c) => + g.complete := c } val hartRegFields = Seq.tabulate(nHarts) { i => @@ -200,9 +215,8 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule }, RegWriteFn { (valid, data) => val irq = data.extract(log2Ceil(nDevices+1)-1, 0) - when (valid && enables(i)(irq)) { - gateways(irq).complete := Bool(true) - } + completingDevs(i) := irq + completer(i) := valid && enables(i)(irq) Bool(true) } ) From 4e9f65b2ef0c8d1b90ab3a8088943ce06e01945f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 30 Jun 2017 10:07:39 -0700 Subject: [PATCH 06/11] Simplify logic further and bugfix complete was being set unconditionally --- src/main/scala/uncore/devices/Plic.scala | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 2f73bdaa..1815fe47 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -197,12 +197,9 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // a time through the TL interface // (Note -- PLIC doesn't care which hart writes the register) val completer = Wire(Vec(nHarts, Bool())) - val completingDevs = Wire(Vec(nHarts, UInt(width = log2Up(pending.size)))) - val completing = Vec.tabulate(nHarts){i => Mux(completer(i), UIntToOH(completingDevs(i), nDevices+1), UInt(0))} - val completedDevs = Vec(completing.reduceLeft( _ | _ ).toBools) - - (gateways zip completedDevs) foreach { case (g, c) => - g.complete := c + val irq = data.extract(log2Ceil(nDevices+1)-1, 0) + when (completer.reduce(_ || _)) { + gateways(irq).complete := Bool(false) } val hartRegFields = Seq.tabulate(nHarts) { i => @@ -214,8 +211,6 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule (Bool(true), maxDevs(i)) }, RegWriteFn { (valid, data) => - val irq = data.extract(log2Ceil(nDevices+1)-1, 0) - completingDevs(i) := irq completer(i) := valid && enables(i)(irq) Bool(true) } From 367d4aebe6df6192749a17860e0488efb37a9395 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 30 Jun 2017 10:15:53 -0700 Subject: [PATCH 07/11] Set complete unconditionally --- src/main/scala/uncore/devices/Plic.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 1815fe47..b56123e3 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -198,8 +198,9 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // (Note -- PLIC doesn't care which hart writes the register) val completer = Wire(Vec(nHarts, Bool())) val irq = data.extract(log2Ceil(nDevices+1)-1, 0) - when (completer.reduce(_ || _)) { - gateways(irq).complete := Bool(false) + val completedDevs = Mux(completer.reduce(_ || _), UIntToOH(irq, nDevices+1), UInt(0)) + (gateways zip completedDevs.toBools) foreach { case (g, c) => + g.complete := c } val hartRegFields = Seq.tabulate(nHarts) { i => From 3da26b0aa8f8d776fa684fa03c72aef5a4313743 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 30 Jun 2017 12:32:58 -0700 Subject: [PATCH 08/11] plic: Add some assertions to check one-hot assumptions --- src/main/scala/uncore/devices/Plic.scala | 26 ++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index b56123e3..7509cd3e 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -176,12 +176,14 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) } - // When a hart reads its claim/complete register, then the + // When a hart reads a claim/complete register, then the // device which is currently its highest priority is no longer pending. - // This code expolits the fact that only one hart can claim a device at - // a time through the TL interface. + // This code expolits the fact that, practically, only one claim/complete + // register can be read at a time. We check for this because if the address map + // were to change, it may no longer be true. // Note: PLIC doesn't care which hart reads the register. val claimer = Wire(Vec(nHarts, Bool())) + assert((claimer.asUInt & (claimer.asUInt - UInt(1))) === UInt(0)) // One-Hot val claiming = Vec.tabulate(nHarts){i => Mux(claimer(i), UIntToOH(maxDevs(i), nDevices+1), UInt(0))} val claimedDevs = Vec(claiming.reduceLeft( _ | _ ).toBools) @@ -193,12 +195,15 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // When a hart writes a claim/complete register, then // the written device (as long as it is actually enabled for that // hart) is marked complete. - // This code expolits the fact that only one hart can complete a device at - // a time through the TL interface + // This code expolits the fact that, practically, only one claim/complete register + // can be written at a time. We check for this because if the address map + // were to change, it may no longer be true. // (Note -- PLIC doesn't care which hart writes the register) val completer = Wire(Vec(nHarts, Bool())) - val irq = data.extract(log2Ceil(nDevices+1)-1, 0) - val completedDevs = Mux(completer.reduce(_ || _), UIntToOH(irq, nDevices+1), UInt(0)) + assert((completer.asUInt & (completer.asUInt - UInt(1))) === UInt(0)) // One-Hot + val completerDev = Wire(UInt(width = log2Up(nDevices + 1))) + val checkCompleterDev = Wire(Vec(nHarts, UInt(width = log2Up(nDevices + 1)))) // For assertion purposes only. + val completedDevs = Mux(completer.reduce(_ || _), UIntToOH(completerDev, nDevices+1), UInt(0)) (gateways zip completedDevs.toBools) foreach { case (g, c) => g.complete := c } @@ -212,7 +217,12 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule (Bool(true), maxDevs(i)) }, RegWriteFn { (valid, data) => - completer(i) := valid && enables(i)(irq) + if (i > 0) { + assert(checkCompleterDev(i-1) === data.extract(log2Ceil(nDevices+1)-1, 0)) + } + checkCompleterDev(i) := data.extract(log2Ceil(nDevices+1)-1, 0) + completer(i) := valid && enables(i)(completerDev) + completerDev := data.extract(log2Ceil(nDevices+1)-1, 0) Bool(true) } ) From 76f8de75e35a805aba1bf877766095b2b6bc190e Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 30 Jun 2017 12:51:09 -0700 Subject: [PATCH 09/11] plic: comment tidying --- src/main/scala/uncore/devices/Plic.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 7509cd3e..d6fff5dd 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -198,7 +198,7 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // This code expolits the fact that, practically, only one claim/complete register // can be written at a time. We check for this because if the address map // were to change, it may no longer be true. - // (Note -- PLIC doesn't care which hart writes the register) + // Note -- PLIC doesn't care which hart writes the register. val completer = Wire(Vec(nHarts, Bool())) assert((completer.asUInt & (completer.asUInt - UInt(1))) === UInt(0)) // One-Hot val completerDev = Wire(UInt(width = log2Up(nDevices + 1))) From f31ae008f39afc0ae341987fb413365a617c88a0 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 30 Jun 2017 14:15:26 -0700 Subject: [PATCH 10/11] plic: Clean up comments and simplify checking --- src/main/scala/uncore/devices/Plic.scala | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index d6fff5dd..150b1db2 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -178,7 +178,7 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // When a hart reads a claim/complete register, then the // device which is currently its highest priority is no longer pending. - // This code expolits the fact that, practically, only one claim/complete + // This code exploits the fact that, practically, only one claim/complete // register can be read at a time. We check for this because if the address map // were to change, it may no longer be true. // Note: PLIC doesn't care which hart reads the register. @@ -195,14 +195,13 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule // When a hart writes a claim/complete register, then // the written device (as long as it is actually enabled for that // hart) is marked complete. - // This code expolits the fact that, practically, only one claim/complete register + // This code exploits the fact that, practically, only one claim/complete register // can be written at a time. We check for this because if the address map // were to change, it may no longer be true. // Note -- PLIC doesn't care which hart writes the register. val completer = Wire(Vec(nHarts, Bool())) assert((completer.asUInt & (completer.asUInt - UInt(1))) === UInt(0)) // One-Hot val completerDev = Wire(UInt(width = log2Up(nDevices + 1))) - val checkCompleterDev = Wire(Vec(nHarts, UInt(width = log2Up(nDevices + 1)))) // For assertion purposes only. val completedDevs = Mux(completer.reduce(_ || _), UIntToOH(completerDev, nDevices+1), UInt(0)) (gateways zip completedDevs.toBools) foreach { case (g, c) => g.complete := c @@ -217,19 +216,15 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule (Bool(true), maxDevs(i)) }, RegWriteFn { (valid, data) => - if (i > 0) { - assert(checkCompleterDev(i-1) === data.extract(log2Ceil(nDevices+1)-1, 0)) - } - checkCompleterDev(i) := data.extract(log2Ceil(nDevices+1)-1, 0) - completer(i) := valid && enables(i)(completerDev) + assert(completerDev === data.extract(log2Ceil(nDevices+1)-1, 0), "completerDev should be constant for all harts") completerDev := data.extract(log2Ceil(nDevices+1)-1, 0) + completer(i) := valid && enables(i)(completerDev) Bool(true) } ) ) } - node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*) priority(0) := 0 From 8c92c50d8544d1d6e40b9cbcfaffc271924cdcc4 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Fri, 30 Jun 2017 14:25:09 -0700 Subject: [PATCH 11/11] plic: make assertion comment right --- src/main/scala/uncore/devices/Plic.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 150b1db2..5eaa7626 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -216,7 +216,8 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule (Bool(true), maxDevs(i)) }, RegWriteFn { (valid, data) => - assert(completerDev === data.extract(log2Ceil(nDevices+1)-1, 0), "completerDev should be constant for all harts") + assert(completerDev === data.extract(log2Ceil(nDevices+1)-1, 0), + "completerDev should be consistent for all harts") completerDev := data.extract(log2Ceil(nDevices+1)-1, 0) completer(i) := valid && enables(i)(completerDev) Bool(true)