2016-11-28 01:16:37 +01:00
// See LICENSE.SiFive for license details.
2016-05-03 00:19:43 +02:00
2017-07-07 19:48:16 +02:00
package freechips.rocketchip.devices.tilelink
2016-05-03 00:19:43 +02:00
import Chisel._
2017-07-23 17:31:04 +02:00
import freechips.rocketchip.config. { Field , Parameters }
import freechips.rocketchip.coreplex.HasPeripheryBus
2017-07-07 19:48:16 +02:00
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
2017-10-20 05:44:54 +02:00
import freechips.rocketchip.interrupts._
2017-07-07 19:48:16 +02:00
import freechips.rocketchip.util._
2016-09-16 07:06:39 +02:00
import scala.math. { min , max }
2016-05-03 00:19:43 +02:00
2016-10-29 06:20:49 +02:00
object ClintConsts
{
2016-09-16 23:26:34 +02:00
def msipOffset ( hart : Int ) = hart * msipBytes
def timecmpOffset ( hart : Int ) = 0x4000 + hart * timecmpBytes
def timeOffset = 0xbff8
2016-06-28 08:05:48 +02:00
def msipBytes = 4
def timecmpBytes = 8
2016-09-16 23:26:34 +02:00
def size = 0x10000
2017-03-02 06:57:00 +01:00
def timeWidth = 64
2017-10-11 02:22:15 +02:00
def ipiWidth = 32
2017-03-02 06:57:00 +01:00
def ints = 2
2016-06-28 08:05:48 +02:00
}
2017-09-06 23:20:46 +02:00
case class ClintParams ( baseAddress : BigInt = 0x02000000 , intStages : Int = 0 )
2017-06-21 01:11:57 +02:00
{
def address = AddressSet ( baseAddress , ClintConsts . size - 1 )
}
2017-09-09 03:33:44 +02:00
case object ClintKey extends Field ( ClintParams ( ) )
2017-07-23 17:31:04 +02:00
2017-06-21 02:21:53 +02:00
class CoreplexLocalInterrupter ( params : ClintParams ) ( implicit p : Parameters ) extends LazyModule
2017-03-02 06:57:00 +01:00
{
import ClintConsts._
2016-06-28 08:05:48 +02:00
2017-03-02 06:57:00 +01:00
// clint0 => at most 4095 devices
val device = new SimpleDevice ( "clint" , Seq ( "riscv,clint0" ) ) {
override val alwaysExtended = true
2016-09-21 00:00:52 +02:00
}
2017-03-02 06:57:00 +01:00
val node = TLRegisterNode (
2017-06-21 01:11:57 +02:00
address = Seq ( params . address ) ,
2017-03-02 06:57:00 +01:00
device = device ,
beatBytes = p ( XLen ) / 8 )
2016-06-28 08:05:48 +02:00
2017-03-02 06:57:00 +01:00
val intnode = IntNexusNode (
2017-11-30 23:43:43 +01:00
sourceFn = { _ => IntSourcePortParameters ( Seq ( IntSourceParameters ( ints , Seq ( Resource ( device , "int" ) ) ) ) ) } ,
sinkFn = { _ => IntSinkPortParameters ( Seq ( IntSinkParameters ( ) ) ) } ,
outputRequiresInput = false )
2016-09-15 03:09:27 +02:00
2017-03-02 06:57:00 +01:00
lazy val module = new LazyModuleImp ( this ) {
2017-11-30 23:43:43 +01:00
require ( intnode . edges . in . size == 0 , "CLINT only produces interrupts; it does not accept them" )
2017-09-14 03:06:03 +02:00
val io = IO ( new Bundle {
2017-03-02 06:57:00 +01:00
val rtcTick = Bool ( INPUT )
2017-09-14 03:06:03 +02:00
} )
2017-03-02 06:57:00 +01:00
2017-10-11 02:22:15 +02:00
val time = RegInit ( UInt ( 0 , width = timeWidth ) )
when ( io . rtcTick ) { time : = time + UInt ( 1 ) }
2017-03-02 06:57:00 +01:00
2017-09-14 03:06:03 +02:00
val nTiles = intnode . out . size
2017-10-11 02:22:15 +02:00
val timecmp = Seq . fill ( nTiles ) { Reg ( UInt ( width = timeWidth ) ) }
2017-06-21 01:11:57 +02:00
val ipi = Seq . fill ( nTiles ) { RegInit ( UInt ( 0 , width = 1 ) ) }
2017-03-02 06:57:00 +01:00
2017-09-28 00:18:42 +02:00
val ( intnode_out , _ ) = intnode . out . unzip
intnode_out . zipWithIndex . foreach { case ( int , i ) =>
2017-09-06 23:20:46 +02:00
int ( 0 ) : = ShiftRegister ( ipi ( i ) ( 0 ) , params . intStages ) // msip
int ( 1 ) : = ShiftRegister ( time . asUInt >= timecmp ( i ) . asUInt , params . intStages ) // mtip
2017-03-02 06:57:00 +01:00
}
/* 0000 msip hart 0
* 0004 msip hart 1
* 4000 mtimecmp hart 0 lo
* 4004 mtimecmp hart 0 hi
* 4008 mtimecmp hart 1 lo
* 400 c mtimecmp hart 1 hi
* bff8 mtime lo
* bffc mtime hi
*/
node . regmap (
2018-02-12 08:57:57 +01:00
0 -> RegFieldGroup ( "msip" , Some ( "MSIP Bits" ) , ipi . zipWithIndex . map { case ( r , i ) => RegField ( ipiWidth , r , RegFieldDesc ( s" msip_ $i " , s" MSIP bit for Hart $i " , reset = Some ( 0 ) ) ) } ) ,
2018-02-12 06:33:09 +01:00
timecmpOffset ( 0 ) -> timecmp . zipWithIndex . flatMap { case ( t , i ) =>
2018-02-12 08:57:57 +01:00
RegFieldGroup ( s" mtimecmp_ $i " , Some ( s" MTIMECMP for hart $i " ) , RegField . bytes ( t , Some ( RegFieldDesc ( s" mtimecmp_ $i " , "" , reset = None ) ) ) ) } ,
2018-02-12 06:33:09 +01:00
timeOffset -> RegFieldGroup ( "mtime" , Some ( "Timer Register" ) , RegField . bytes ( time , Some ( RegFieldDesc ( "mtime" , "" , reset = Some ( 0 ) ) ) ) )
)
2016-11-22 23:58:03 +01:00
}
}
2017-07-23 17:31:04 +02:00
/* * Trait that will connect a Clint to a coreplex */
trait HasPeripheryClint extends HasPeripheryBus {
2017-09-09 03:33:44 +02:00
val clint = LazyModule ( new CoreplexLocalInterrupter ( p ( ClintKey ) ) )
2017-07-23 17:31:04 +02:00
clint . node : = pbus . toVariableWidthSlaves
}