1
0

Refactor package hierarchy and remove legacy bus protocol implementations (#845)

* Refactors package hierarchy.

Additionally:
  - Removes legacy ground tests and configs
  - Removes legacy bus protocol implementations
  - Removes NTiles
  - Adds devices package
  - Adds more functions to util package
This commit is contained in:
Henry Cook
2017-07-07 10:48:16 -07:00
committed by GitHub
parent c28c23150d
commit 4c595d175c
238 changed files with 1347 additions and 10978 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
// This file was auto-generated by 'make publish' in debug/ directory.
package freechips.rocketchip.devices.debug
object DebugRomContents {
def apply() : Array[Byte] = { Array (
0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0xc0, 0x04, 0x6f, 0x00, 0x40, 0x03,
0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1,
0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00,
0x63, 0x10, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40,
0x13, 0x74, 0x24, 0x00, 0xe3, 0x18, 0x04, 0xfc, 0x6f, 0xf0, 0xdf, 0xfd,
0x23, 0x26, 0x00, 0x10, 0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x20, 0x7b,
0x23, 0x22, 0x00, 0x10, 0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1,
0x23, 0x24, 0x80, 0x10, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b
).map(_.toByte) }
}

View File

@ -0,0 +1,68 @@
package freechips.rocketchip.devices.debug
import Chisel._
// This file was auto-generated from the repository at https://github.com/sifive/riscv-debug-spec.git,
// 'make chisel'
object AC_RegAddrs {
}
class ACCESS_REGISTERFields extends Bundle {
/* This is 0 to indicate Access Register Command.
*/
val cmdtype = UInt(8.W)
val reserved0 = UInt(1.W)
/* 2: Access the lowest 32 bits of the register.
3: Access the lowest 64 bits of the register.
4: Access the lowest 128 bits of the register.
If \Fsize specifies a size larger than the register's actual size,
then the access must fail. If a register is accessible, then reads of \Fsize
less than or equal to the register's actual size must be supported.
*/
val size = UInt(3.W)
val reserved1 = UInt(1.W)
/* When 1, execute the program in the Program Buffer exactly once
after performing the transfer, if any.
*/
val postexec = Bool()
/* 0: Don't do the operation specified by \Fwrite.
1: Do the operation specified by \Fwrite.
*/
val transfer = Bool()
/* When \Ftransfer is set:
0: Copy data from the specified register into {\tt arg0} portion
of {\tt data}.
1: Copy data from {\tt arg0} portion of {\tt data} into the
specified register.
*/
val write = Bool()
/* Number of the register to access, as described in Table~\ref{tab:regno}.
*/
val regno = UInt(16.W)
}
class QUICK_ACCESSFields extends Bundle {
/* This is 1 to indicate Quick Access command.
*/
val cmdtype = UInt(8.W)
val reserved0 = UInt(24.W)
}

View File

@ -0,0 +1,859 @@
package freechips.rocketchip.devices.debug
import Chisel._
// This file was auto-generated from the repository at https://github.com/sifive/riscv-debug-spec.git,
// 'make chisel'
object DMI_RegAddrs {
/* The address of this register will not change in the future, because it
contains \Fversion. It has changed from version 0.11 of this spec.
This register reports status for the overall debug module
as well as the currently selected harts, as defined in \Fhasel.
*/
def DMI_DMSTATUS = 0x11
/* This register controls the overall debug module
as well as the currently selected harts, as defined in \Fhasel.
*/
def DMI_DMCONTROL = 0x10
/* This register gives information about the hart currently
selected by \Fhartsel.
This register is optional. If it is not present it should
read all-zero.
If this register is included, the debugger can do more with
the Program Buffer by writing programs which
explicitly access the {\tt data} and/or {\tt dscratch}
registers.
*/
def DMI_HARTINFO = 0x12
/* This register contains a summary of which harts are halted.
Each bit contains the logical OR of 32 halt bits. When there are a
large number of harts in the system, the debugger can first read this
register, and then read from the halt region (0x40--0x5f) to determine
which hart is the one that is halted.
*/
def DMI_HALTSUM = 0x13
/* This register selects which of the 32-bit portion of the hart array mask register
is accessible in \Rhawindow.
The hart array mask register provides a mask of all harts controlled by
the debug module. A hart is part of the currently selected harts if
the corresponding bit is set in the hart array mask register and
\Fhasel in \Rdmcontrol is 1, or if the hart is selected by \Fhartsel.
*/
def DMI_HAWINDOWSEL = 0x14
/* This register provides R/W access to a 32-bit portion of the
hart array mask register. The position of the window is determined by
\Rhawindowsel.
*/
def DMI_HAWINDOW = 0x15
def DMI_ABSTRACTCS = 0x16
/* Writes to this register cause the corresponding abstract command to be
executed.
Writing while an abstract command is executing causes \Fcmderr to be set.
If \Fcmderr is non-zero, writes to this register are ignored.
\begin{commentary}
\Fcmderr inhibits starting a new command to accommodate debuggers
that, for performance reasons, send several commands to be executed
in a row without checking \Fcmderr in between. They can safely do
so and check \Fcmderr at the end without worrying that one command
failed but then a later command (which might have depended on the
previous one succeeding) passed.
\end{commentary}
*/
def DMI_COMMAND = 0x17
/* This register is optional. Including it allows more efficient burst accesses.
Debugger can attempt to set bits and read them back to determine if the functionality is supported.
*/
def DMI_ABSTRACTAUTO = 0x18
/* The Configuration String is described in the RISC-V Priviledged Specification.
When {\tt cfgstrvalid} is set, reading this register returns bits 31:0 of the configuration
string address. Reading the other {\tt cfgstraddr} registers returns the upper bits of the
address.
When system bus mastering is implemented, this should be the
address that should be used with the System Bus Access module. Otherwise,
this should be the address that should be used to access the
config string when \Fhartsel=0.
If {\tt cfgstrvalid} is 0, then the {\tt cfgstraddr} registers
hold identifier information which is not
further specified in this document.
*/
def DMI_CFGSTRADDR0 = 0x19
def DMI_CFGSTRADDR1 = 0x1a
def DMI_CFGSTRADDR2 = 0x1b
def DMI_CFGSTRADDR3 = 0x1c
/* Basic read/write registers that may be read or changed by abstract
commands.
Accessing them while an abstract command is executing causes \Fcmderr
to be set.
The values in these registers may not be preserved after an abstract
command is executed. The only guarantees on their contents are the ones
offered by the command in question. If the command fails, no
assumptions can be made about the contents of these registers.
*/
def DMI_DATA0 = 0x04
def DMI_DATA11 = 0x0f
/* The {\tt progbuf} registers provide read/write access to the optional
program buffer.
*/
def DMI_PROGBUF0 = 0x20
def DMI_PROGBUF15 = 0x2f
/* This register serves as a 32-bit serial port to the authentication
module.
When \Fauthbusy is clear, the debugger can communicate with the
authentication module by reading or writing this register. There is no
separate mechanism to signal overflow/underflow.
*/
def DMI_AUTHDATA = 0x30
/* If \Fserialcount is 0, this register is not present.
*/
def DMI_SERCS = 0x34
/* If \Fserialcount is 0, this register is not present.
This register provides access to the write data queue of the serial port
selected by \Fserial in \Rsercs.
If the {\tt error} bit is not set and the queue is not full, a write to this register
adds the written data to the core-to-debugger queue.
Otherwise the {\tt error} bit is set and the write returns error.
A read to this register returns the last data written.
*/
def DMI_SERTX = 0x35
/* If \Fserialcount is 0, this register is not present.
This register provides access to the read data queues of the serial port
selected by \Fserial in \Rsercs.
If the {\tt error} bit is not set and the queue is not empty, a read from this register reads the
oldest entry in the debugger-to-core queue, and removes that entry from the queue.
Otherwise the {\tt error} bit is set and the read returns error.
*/
def DMI_SERRX = 0x36
def DMI_SBCS = 0x38
/* If \Fsbasize is 0, then this register is not present.
When the system bus master is busy,
writes to this register will return error
and \Fsberror is set.
If \Fsberror is 0 and \Fsbautoread is set then the system bus
master will start
to read after updating the address from \Faddress. The access size is
controlled by \Fsbaccess in \Rsbcs.
If \Fsbsingleread is set, the bit is cleared.
*/
def DMI_SBADDRESS0 = 0x39
def DMI_SBADDRESS1 = 0x3a
/* If \Fsbasize is less than 65, then this register is not present.
*/
def DMI_SBADDRESS2 = 0x3b
/* If all of the {\tt sbaccess} bits in \Rsbcs are 0, then this register
is not present.
If \Fsberror isn't 0 then accesses return error, and don't do anything
else.
Writes to this register:
1. If the bus master is busy then accesses set \Fsberror, return error,
and don't do anything else.
2. Update internal data.
3. Start a bus write of the internal data to the internal address.
4. If \Fsbautoincrement is set, increment the internal address.
Reads to this register:
1. If bits 31:0 of the internal data register haven't been updated
since the last time this register was read, then set \Fsberror, return
error, and don't do anything else.
2. ``Return'' the data.
3. If \Fsbautoincrement is set, increment the internal address.
4. If \Fsbautoread is set, start another system bus read.
*/
def DMI_SBDATA0 = 0x3c
/* If \Fsbaccesssixtyfour and \Fsbaccessonetwentyeight are 0, then this
register is not present.
*/
def DMI_SBDATA1 = 0x3d
/* This register only exists if \Fsbaccessonetwentyeight is 1.
*/
def DMI_SBDATA2 = 0x3e
/* This register only exists if \Fsbaccessonetwentyeight is 1.
*/
def DMI_SBDATA3 = 0x3f
}
class DMSTATUSFields extends Bundle {
val reserved0 = UInt(14.W)
/* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq.
*/
val allresumeack = Bool()
/* This field is 1 when any currently selected hart has acknowledged the previous \Fresumereq.
*/
val anyresumeack = Bool()
/* This field is 1 when all currently selected harts do not exist in this system.
*/
val allnonexistent = Bool()
/* This field is 1 when any currently selected hart does not exist in this system.
*/
val anynonexistent = Bool()
/* This field is 1 when all currently selected harts are unavailable.
*/
val allunavail = Bool()
/* This field is 1 when any currently selected hart is unavailable.
*/
val anyunavail = Bool()
/* This field is 1 when all currently selected harts are running.
*/
val allrunning = Bool()
/* This field is 1 when any currently selected hart is running.
*/
val anyrunning = Bool()
/* This field is 1 when all currently selected harts are halted.
*/
val allhalted = Bool()
/* This field is 1 when any currently selected hart is halted.
*/
val anyhalted = Bool()
/* 0 when authentication is required before using the DM. 1 when the
authentication check has passed. On components that don't implement
authentication, this bit must be preset as 1.
*/
val authenticated = Bool()
/* 0: The authentication module is ready to process the next
read/write to \Rauthdata.
1: The authentication module is busy. Accessing \Rauthdata results
in unspecified behavior.
\Fauthbusy only becomes set in immediate response to an access to
\Rauthdata.
*/
val authbusy = Bool()
val reserved1 = UInt(1.W)
val cfgstrvalid = Bool()
/* Reserved for future use. Reads as 0.
*/
val versionhi = UInt(2.W)
/* 00: There is no Debug Module present.
01: There is a Debug Module and it conforms to version 0.11 of this
specification.
10: There is a Debug Module and it conforms to version 0.13 of this
specification.
11: Reserved for future use.
*/
val versionlo = UInt(2.W)
}
class DMCONTROLFields extends Bundle {
/* Halt request signal for all currently selected harts. When set to 1, the
hart will halt if it is not currently halted.
Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val haltreq = Bool()
/* Resume request signal for all currently selected harts. When set to 1,
the hart will resume if it is currently halted.
Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val resumereq = Bool()
/* This optional bit controls reset to all the currently selected harts.
To perform a reset the debugger writes 1, and then writes 0 to
deassert the reset signal.
If this feature is not implemented, the bit always stays 0, so
after writing 1 the debugger can read the register back to see if
the feature is supported.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val hartreset = Bool()
val reserved0 = UInt(2.W)
/* Selects the definition of currently selected harts.
0: There is a single currently selected hart, that selected by \Fhartsel.
1: There may be multiple currently selected harts -- that selected by \Fhartsel,
plus those selected by the hart array mask register.
An implementation which does not implement the hart array mask register
should tie this field to 0. A debugger which wishes to use the hart array
mask register feature should set this bit and read back to see if the functionality
is supported.
*/
val hasel = Bool()
/* The DM-specific index of the hart to select. This hart is always part of the
currently selected harts.
*/
val hartsel = UInt(10.W)
val reserved1 = UInt(14.W)
/* This bit controls the reset signal from the DM to the rest of the
system. To perform a reset the debugger writes 1, and then writes 0
to deassert the reset.
*/
val ndmreset = Bool()
/* This bit serves as a reset signal for the Debug Module itself.
0: The module's state, including authentication mechanism,
takes its reset values (the \Fdmactive bit is the only bit which can
be written to something other than its reset value).
1: The module functions normally.
No other mechanism should exist that may result in resetting the
Debug Module after power up, including the platform's system reset
or Debug Transport reset signals.
A debugger should pulse this bit low to ensure that the Debug
Module is fully reset and ready to use.
Implementations may use this bit to aid debugging, for example by
preventing the Debug Module from being power gated while debugging
is active.
*/
val dmactive = Bool()
}
class HARTINFOFields extends Bundle {
val reserved0 = UInt(8.W)
/* Number of {\tt dscratch} registers available for the debugger
to use during program buffer execution, starting from \Rdscratchzero.
The debugger can make no assumptions about the contents of these
registers between commands.
*/
val nscratch = UInt(4.W)
val reserved1 = UInt(3.W)
/* 0: The {\tt data} registers are shadowed in the hart by CSR
registers. Each CSR register is XLEN bits in size, and corresponds
to a single argument, per Table~\ref{tab:datareg}.
1: The {\tt data} registers are shadowed in the hart's memory map.
Each register takes up 4 bytes in the memory map.
*/
val dataaccess = Bool()
/* If \Fdataaccess is 0: Number of CSR registers dedicated to
shadowing the {\tt data} registers.
If \Fdataaccess is 1: Number of 32-bit words in the memory map
dedicated to shadowing the {\tt data} registers.
*/
val datasize = UInt(4.W)
/* If \Fdataaccess is 0: The number of the first CSR dedicated to
shadowing the {\tt data} registers.
If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
registers are shadowed.
*/
val dataaddr = UInt(12.W)
}
class HALTSUMFields extends Bundle {
val halt1023_992 = Bool()
val halt991_960 = Bool()
val halt959_928 = Bool()
val halt927_896 = Bool()
val halt895_864 = Bool()
val halt863_832 = Bool()
val halt831_800 = Bool()
val halt799_768 = Bool()
val halt767_736 = Bool()
val halt735_704 = Bool()
val halt703_672 = Bool()
val halt671_640 = Bool()
val halt639_608 = Bool()
val halt607_576 = Bool()
val halt575_544 = Bool()
val halt543_512 = Bool()
val halt511_480 = Bool()
val halt479_448 = Bool()
val halt447_416 = Bool()
val halt415_384 = Bool()
val halt383_352 = Bool()
val halt351_320 = Bool()
val halt319_288 = Bool()
val halt287_256 = Bool()
val halt255_224 = Bool()
val halt223_192 = Bool()
val halt191_160 = Bool()
val halt159_128 = Bool()
val halt127_96 = Bool()
val halt95_64 = Bool()
val halt63_32 = Bool()
val halt31_0 = Bool()
}
class HAWINDOWSELFields extends Bundle {
val reserved0 = UInt(27.W)
val hawindowsel = UInt(5.W)
}
class HAWINDOWFields extends Bundle {
val maskdata = UInt(32.W)
}
class ABSTRACTCSFields extends Bundle {
val reserved0 = UInt(3.W)
/* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
TODO: Explain what can be done with each size of the buffer, to suggest
why you would want more or less words.
*/
val progsize = UInt(5.W)
val reserved1 = UInt(11.W)
/* 1: An abstract command is currently being executed.
This bit is set as soon as \Rcommand is written, and is
not cleared until that command has completed.
*/
val busy = Bool()
val reserved2 = UInt(1.W)
/* Gets set if an abstract command fails. The bits in this field remain set until
they are cleared by writing 1 to them. No abstract command is
started until the value is reset to 0.
0 (none): No error.
1 (busy): An abstract command was executing while \Rcommand or one
of the {\tt data} registers was accessed.
2 (not supported): The requested command is not supported. A
command that is not supported while the hart is running may be
supported when it is halted.
3 (exception): An exception occurred while executing the command
(eg. while executing the Program Buffer).
4 (halt/resume): An abstract command couldn't execute because the
hart wasn't in the expected state (running/halted).
7 (other): The command failed for another reason.
*/
val cmderr = UInt(3.W)
val reserved3 = UInt(3.W)
/* Number of {\tt data} registers that are implemented as part of the
abstract command interface. Valid sizes are 0 - 8.
*/
val datacount = UInt(5.W)
}
class COMMANDFields extends Bundle {
/* The type determines the overall functionality of this
abstract command.
*/
val cmdtype = UInt(8.W)
/* This field is interpreted in a command-specific manner,
described for each abstract command.
*/
val control = UInt(24.W)
}
class ABSTRACTAUTOFields extends Bundle {
/* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word
cause the command in \Rcommand to be executed again.
*/
val autoexecprogbuf = UInt(16.W)
val reserved0 = UInt(4.W)
/* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word
cause the command in \Rcommand to be executed again.
*/
val autoexecdata = UInt(12.W)
}
class CFGSTRADDR0Fields extends Bundle {
val addr = UInt(32.W)
}
class DATA0Fields extends Bundle {
val data = UInt(32.W)
}
class PROGBUF0Fields extends Bundle {
val data = UInt(32.W)
}
class AUTHDATAFields extends Bundle {
val data = UInt(32.W)
}
class SERCSFields extends Bundle {
/* Number of supported serial ports.
*/
val serialcount = UInt(4.W)
val reserved0 = UInt(1.W)
/* Select which serial port is accessed by \Rserrx and \Rsertx.
*/
val serial = UInt(3.W)
val error7 = Bool()
val valid7 = Bool()
val full7 = Bool()
val error6 = Bool()
val valid6 = Bool()
val full6 = Bool()
val error5 = Bool()
val valid5 = Bool()
val full5 = Bool()
val error4 = Bool()
val valid4 = Bool()
val full4 = Bool()
val error3 = Bool()
val valid3 = Bool()
val full3 = Bool()
val error2 = Bool()
val valid2 = Bool()
val full2 = Bool()
val error1 = Bool()
val valid1 = Bool()
val full1 = Bool()
/* 1 when the debugger-to-core queue for serial port 0 has
over or underflowed. This bit will remain set until it is reset by
writing 1 to this bit.
*/
val error0 = Bool()
/* 1 when the core-to-debugger queue for serial port 0 is not empty.
*/
val valid0 = Bool()
/* 1 when the debugger-to-core queue for serial port 0 is full.
*/
val full0 = Bool()
}
class SERTXFields extends Bundle {
val data = UInt(32.W)
}
class SERRXFields extends Bundle {
val data = UInt(32.W)
}
class SBCSFields extends Bundle {
val reserved0 = UInt(11.W)
/* When a 1 is written here, triggers a read at the address in {\tt
sbaddress} using the access size set by \Fsbaccess.
*/
val sbsingleread = Bool()
/* Select the access size to use for system bus accesses triggered by
writes to the {\tt sbaddress} registers or \Rsbdatazero.
0: 8-bit
1: 16-bit
2: 32-bit
3: 64-bit
4: 128-bit
If an unsupported system bus access size is written here,
the DM may not perform the access, or may perform the access
with any access size.
*/
val sbaccess = UInt(3.W)
/* When 1, the internal address value (used by the system bus master)
is incremented by the access size (in bytes) selected in \Fsbaccess
after every system bus access.
*/
val sbautoincrement = Bool()
/* When 1, every read from \Rsbdatazero automatically triggers a system
bus read at the new address.
*/
val sbautoread = Bool()
/* When the debug module's system bus
master causes a bus error, this field gets set. The bits in this
field remain set until they are cleared by writing 1 to them.
While this field is non-zero, no more system bus accesses can be
initiated by the debug module.
0: There was no bus error.
1: There was a timeout.
2: A bad address was accessed.
3: There was some other error (eg. alignment).
4: The system bus master was busy when a one of the
{\tt sbaddress} or {\tt sbdata} registers was written,
or the {\tt sbdata} register was read when it had
stale data.
*/
val sberror = UInt(3.W)
/* Width of system bus addresses in bits. (0 indicates there is no bus
access support.)
*/
val sbasize = UInt(7.W)
/* 1 when 128-bit system bus accesses are supported.
*/
val sbaccess128 = Bool()
/* 1 when 64-bit system bus accesses are supported.
*/
val sbaccess64 = Bool()
/* 1 when 32-bit system bus accesses are supported.
*/
val sbaccess32 = Bool()
/* 1 when 16-bit system bus accesses are supported.
*/
val sbaccess16 = Bool()
/* 1 when 8-bit system bus accesses are supported.
*/
val sbaccess8 = Bool()
}
class SBADDRESS0Fields extends Bundle {
/* Accesses bits 31:0 of the internal address.
*/
val address = UInt(32.W)
}
class SBADDRESS1Fields extends Bundle {
/* Accesses bits 63:32 of the internal address (if the system address
bus is that wide).
*/
val address = UInt(32.W)
}
class SBADDRESS2Fields extends Bundle {
/* Accesses bits 95:64 of the internal address (if the system address
bus is that wide).
*/
val address = UInt(32.W)
}
class SBDATA0Fields extends Bundle {
/* Accesses bits 31:0 of the internal data.
*/
val data = UInt(32.W)
}
class SBDATA1Fields extends Bundle {
/* Accesses bits 63:32 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}
class SBDATA2Fields extends Bundle {
/* Accesses bits 95:64 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}
class SBDATA3Fields extends Bundle {
/* Accesses bits 127:96 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}

View File

@ -0,0 +1,92 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import scala.math.{min,max}
object ClintConsts
{
def msipOffset(hart: Int) = hart * msipBytes
def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
def timeOffset = 0xbff8
def msipBytes = 4
def timecmpBytes = 8
def size = 0x10000
def timeWidth = 64
def regWidth = 32
def ints = 2
}
case class ClintParams(baseAddress: BigInt = 0x02000000)
{
def address = AddressSet(baseAddress, ClintConsts.size-1)
}
class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) extends LazyModule
{
import ClintConsts._
// clint0 => at most 4095 devices
val device = new SimpleDevice("clint", Seq("riscv,clint0")) {
override val alwaysExtended = true
}
val node = TLRegisterNode(
address = Seq(params.address),
device = device,
beatBytes = p(XLen)/8)
val intnode = IntNexusNode(
numSourcePorts = 0 to 1024,
numSinkPorts = 0 to 0,
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(ints, Seq(Resource(device, "int"))))) },
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val rtcTick = Bool(INPUT)
val int = intnode.bundleOut
val in = node.bundleIn
}
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
when (io.rtcTick) {
val newTime = time.asUInt + UInt(1)
for ((reg, i) <- time zip (0 until timeWidth by regWidth))
reg := newTime >> i
}
val nTiles = intnode.edgesOut.size
val timecmp = Seq.fill(nTiles) { Seq.fill(timeWidth/regWidth)(Reg(UInt(width = regWidth))) }
val ipi = Seq.fill(nTiles) { RegInit(UInt(0, width = 1)) }
io.int.zipWithIndex.foreach { case (int, i) =>
int(0) := ipi(i)(0) // msip
int(1) := time.asUInt >= timecmp(i).asUInt // mtip
}
/* 0000 msip hart 0
* 0004 msip hart 1
* 4000 mtimecmp hart 0 lo
* 4004 mtimecmp hart 0 hi
* 4008 mtimecmp hart 1 lo
* 400c mtimecmp hart 1 hi
* bff8 mtime lo
* bffc mtime hi
*/
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
node.regmap(
0 -> makeRegFields(ipi),
timecmpOffset(0) -> makeRegFields(timecmp.flatten),
timeOffset -> makeRegFields(time))
}
}

View File

@ -0,0 +1,57 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
class TLError(address: Seq[AddressSet], beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
{
val device = new SimpleDevice("error-device", Seq("sifive,error0"))
val node = TLManagerNode(Seq(TLManagerPortParameters(
Seq(TLManagerParameters(
address = address,
resources = device.reg("mem"),
supportsGet = TransferSizes(1, beatBytes),
supportsPutPartial = TransferSizes(1, beatBytes),
supportsPutFull = TransferSizes(1, beatBytes),
supportsArithmetic = TransferSizes(1, beatBytes),
supportsLogical = TransferSizes(1, beatBytes),
supportsHint = TransferSizes(1, beatBytes),
fifoId = Some(0))), // requests are handled in order
beatBytes = beatBytes,
minLatency = 1))) // no bypass needed for this device
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val in = node.bundleIn
}
import TLMessages._
val opcodes = Vec(AccessAck, AccessAck, AccessAckData, AccessAckData, AccessAckData, HintAck)
val in = io.in(0)
val a = Queue(in.a, 1)
val d = in.d
a.ready := d.ready
d.valid := a.valid
d.bits.opcode := opcodes(a.bits.opcode)
d.bits.param := UInt(0)
d.bits.size := a.bits.size
d.bits.source := a.bits.source
d.bits.sink := UInt(0)
d.bits.addr_lo := a.bits.address
d.bits.data := UInt(0)
d.bits.error := a.bits.opcode =/= Hint // Hints may not error
// Tie off unused channels
in.b.valid := Bool(false)
in.c.ready := Bool(true)
in.e.ready := Bool(true)
}
}

View File

@ -0,0 +1,233 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import Chisel.ImplicitConversions._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import scala.math.min
class GatewayPLICIO extends Bundle {
val valid = Bool(OUTPUT)
val ready = Bool(INPUT)
val complete = Bool(INPUT)
}
class LevelGateway extends Module {
val io = new Bundle {
val interrupt = Bool(INPUT)
val plic = new GatewayPLICIO
}
val inFlight = Reg(init=Bool(false))
when (io.interrupt && io.plic.ready) { inFlight := true }
when (io.plic.complete) { inFlight := false }
io.plic.valid := io.interrupt && !inFlight
}
object PLICConsts
{
def maxDevices = 1023
def maxHarts = 15872
def priorityBase = 0x0
def pendingBase = 0x1000
def enableBase = 0x2000
def hartBase = 0x200000
def claimOffset = 4
def priorityBytes = 4
def enableOffset(i: Int) = i * ((maxDevices+7)/8)
def hartOffset(i: Int) = i * 0x1000
def enableBase(i: Int):Int = enableOffset(i) + enableBase
def hartBase(i: Int):Int = hartOffset(i) + hartBase
def size = hartBase(maxHarts)
require(hartBase >= enableBase(maxHarts))
}
case class PLICParams(baseAddress: BigInt = 0xC000000, maxPriorities: Int = 7)
{
require (maxPriorities >= 0)
def address = AddressSet(baseAddress, PLICConsts.size-1)
}
/** Platform-Level Interrupt Controller */
class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
{
// plic0 => max devices 1023
val device = new SimpleDevice("interrupt-controller", Seq("riscv,plic0")) {
override val alwaysExtended = true
override def describe(resources: ResourceBindings): Description = {
val Description(name, mapping) = super.describe(resources)
val extra = Map(
"interrupt-controller" -> Nil,
"riscv,ndev" -> Seq(ResourceInt(nDevices)),
"#interrupt-cells" -> Seq(ResourceInt(1)))
Description(name, mapping ++ extra)
}
}
val node = TLRegisterNode(
address = Seq(params.address),
device = device,
beatBytes = p(XLen)/8,
undefZero = true,
concurrency = 1) // limiting concurrency handles RAW hazards on claim registers
val intnode = IntNexusNode(
numSourcePorts = 0 to 1024,
numSinkPorts = 0 to 1024,
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Seq(Resource(device, "int"))))) },
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
/* Negotiated sizes */
def nDevices: Int = intnode.edgesIn.map(_.source.num).sum
def nPriorities = min(params.maxPriorities, nDevices)
def nHarts = intnode.edgesOut.map(_.source.num).sum
// Assign all the devices unique ranges
lazy val sources = intnode.edgesIn.map(_.source)
lazy val flatSources = (sources zip sources.map(_.num).scanLeft(0)(_+_).init).map {
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
}.flatten
ResourceBinding {
flatSources.foreach { s => s.resources.foreach { r =>
// +1 because interrupt 0 is reserved
(s.range.start until s.range.end).foreach { i => r.bind(device, ResourceInt(i+1)) }
} }
}
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl_in = node.bundleIn
val devices = intnode.bundleIn
val harts = intnode.bundleOut
}
// Compact the interrupt vector the same way
val interrupts = (intnode.edgesIn zip io.devices).map { case (e, i) => i.take(e.source.num) }.flatten
// This flattens the harts into an MSMSMSMSMS... or MMMMM.... sequence
val harts = io.harts.flatten
println(s"Interrupt map (${nHarts} harts ${nDevices} interrupts):")
flatSources.foreach { s =>
// +1 because 0 is reserved, +1-1 because the range is half-open
println(s" [${s.range.start+1}, ${s.range.end}] => ${s.name}")
}
println("")
require (nDevices == interrupts.size)
require (nHarts == harts.size)
require(nDevices <= PLICConsts.maxDevices)
require(nHarts > 0 && nHarts <= PLICConsts.maxHarts)
// For now, use LevelGateways for all TL2 interrupts
val gateways = Vec((false.B +: interrupts).map { case i =>
val gateway = Module(new LevelGateway)
gateway.io.interrupt := i
gateway.io.plic
})
val priority =
if (nPriorities > 0) Reg(Vec(nDevices+1, UInt(width=log2Up(nPriorities+1))))
else Wire(init=Vec.fill(nDevices+1)(UInt(1)))
val threshold =
if (nPriorities > 0) Reg(Vec(nHarts, UInt(width = log2Up(nPriorities+1))))
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())))
def findMax(x: Seq[UInt]): (UInt, UInt) = {
if (x.length > 1) {
val half = 1 << (log2Ceil(x.length) - 1)
val left = findMax(x take half)
val right = findMax(x drop half)
MuxT(left._1 >= right._1, left, (right._1, UInt(half) | right._2))
} else (x.head, UInt(0))
}
val maxDevs = Reg(Vec(nHarts, UInt(width = log2Up(pending.size))))
for (hart <- 0 until nHarts) {
val effectivePriority = (UInt(1) << priority(0).getWidth) +:
(for (((p, en), pri) <- (pending zip enables(hart) zip priority).tail)
yield Cat(p && en, pri))
val (maxPri, maxDev) = findMax(effectivePriority)
maxDevs(hart) := maxDev
harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
}
def priorityRegField(x: UInt) = if (nPriorities > 0) RegField(32, x) else RegField.r(32, x)
val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p)))
val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b)))
val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
PLICConsts.enableBase(i) -> e.map(b => RegField(1, b))
}
// When a hart reads a claim/complete register, then the
// device which is currently its highest priority is no longer pending.
// 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.
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)
((pending zip gateways) zip claimedDevs) foreach { case ((p, g), c) =>
g.ready := !p
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 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 completedDevs = Mux(completer.reduce(_ || _), UIntToOH(completerDev, nDevices+1), UInt(0))
(gateways zip completedDevs.toBools) foreach { case (g, c) =>
g.complete := c
}
val hartRegFields = Seq.tabulate(nHarts) { i =>
PLICConsts.hartBase(i) -> Seq(
priorityRegField(threshold(i)),
RegField(32,
RegReadFn { valid =>
claimer(i) := valid
(Bool(true), maxDevs(i))
},
RegWriteFn { (valid, data) =>
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)
}
)
)
}
node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*)
priority(0) := 0
pending(0) := false
for (e <- enables)
e(0) := false
}
}

View File

@ -0,0 +1,52 @@
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4,
resources: Seq[Resource] = new SimpleDevice("rom", Seq("sifive,rom0")).reg("mem"))(implicit p: Parameters) extends LazyModule
{
val node = TLManagerNode(beatBytes, TLManagerParameters (
address = List(AddressSet(base, size-1)),
resources = resources,
regionType = RegionType.UNCACHED,
executable = executable,
supportsGet = TransferSizes(1, beatBytes),
fifoId = Some(0)))
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val in = node.bundleIn
}
val contents = contentsDelayed
val wrapSize = 1 << log2Ceil(contents.size)
require (wrapSize <= size)
val in = io.in(0)
val edge = node.edgesIn(0)
val words = (contents ++ Seq.fill(wrapSize-contents.size)(0.toByte)).grouped(beatBytes).toSeq
val bigs = words.map(_.foldRight(BigInt(0)){ case (x,y) => (x.toInt & 0xff) | y << 8})
val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))
in.d.valid := in.a.valid
in.a.ready := in.d.ready
val index = in.a.bits.address(log2Ceil(wrapSize)-1,log2Ceil(beatBytes))
val high = if (wrapSize == size) UInt(0) else in.a.bits.address(log2Ceil(size)-1, log2Ceil(wrapSize))
in.d.bits := edge.AccessAck(in.a.bits, UInt(0), Mux(high.orR, UInt(0), rom(index)))
// Tie off unused channels
in.b.valid := Bool(false)
in.c.ready := Bool(true)
in.e.ready := Bool(true)
}
}

View File

@ -0,0 +1,84 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
// Do not use this for synthesis! Only for simulation.
class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
{
val device = new MemoryDevice
val node = TLManagerNode(Seq(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(address),
resources = device.reg,
regionType = RegionType.UNCACHED,
executable = executable,
supportsGet = TransferSizes(1, beatBytes),
supportsPutPartial = TransferSizes(1, beatBytes),
supportsPutFull = TransferSizes(1, beatBytes),
fifoId = Some(0))), // requests are handled in order
beatBytes = beatBytes)))
// We require the address range to include an entire beat (for the write mask)
require ((address.mask & (beatBytes-1)) == beatBytes-1)
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val in = node.bundleIn
}
def bigBits(x: BigInt, tail: List[Boolean] = List.empty[Boolean]): List[Boolean] =
if (x == 0) tail.reverse else bigBits(x >> 1, ((x & 1) == 1) :: tail)
val mask = bigBits(address.mask >> log2Ceil(beatBytes))
val in = io.in(0)
val edge = node.edgesIn(0)
val addrBits = (mask zip edge.addr_hi(in.a.bits).toBools).filter(_._1).map(_._2)
val memAddress = Cat(addrBits.reverse)
val mem = Mem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8)))
// "Flow control"
in.a.ready := in.d.ready
in.d.valid := in.a.valid
val hasData = edge.hasData(in.a.bits)
val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) }
in.d.bits := edge.AccessAck(in.a.bits, UInt(0))
in.d.bits.data := Cat(mem(memAddress).reverse)
in.d.bits.opcode := Mux(hasData, TLMessages.AccessAck, TLMessages.AccessAckData)
when (in.a.fire() && hasData) { mem.write(memAddress, wdata, in.a.bits.mask.toBools) }
// Tie off unused channels
in.b.valid := Bool(false)
in.c.ready := Bool(true)
in.e.ready := Bool(true)
}
}
/** Synthesizeable unit testing */
import freechips.rocketchip.unittest._
class TLRAMZeroDelay(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
val fuzz = LazyModule(new TLFuzzer(txns))
val model = LazyModule(new TLRAMModel("ZeroDelay"))
val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes))
model.node := fuzz.node
ram.node := TLDelayer(0.25)(model.node)
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
io.finished := fuzz.module.io.finished
}
}
class TLRAMZeroDelayTest(ramBeatBytes: Int, txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
io.finished := Module(LazyModule(new TLRAMZeroDelay(ramBeatBytes, txns)).module).io.finished
}

View File

@ -0,0 +1,48 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.devices.tilelink
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
class TLZero(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
{
val device = new SimpleDevice("rom", Seq("ucbbar,cacheable-zero0"))
val node = TLManagerNode(Seq(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(address),
resources = device.reg("mem"),
regionType = RegionType.UNCACHED,
executable = executable,
supportsGet = TransferSizes(1, beatBytes),
supportsPutPartial = TransferSizes(1, beatBytes),
supportsPutFull = TransferSizes(1, beatBytes),
fifoId = Some(0))), // requests are handled in order
beatBytes = beatBytes,
minLatency = 1))) // no bypass needed for this device
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val in = node.bundleIn
}
val in = io.in(0)
val edge = node.edgesIn(0)
val a = Queue(in.a, 2)
val hasData = edge.hasData(a.bits)
a.ready := in.d.ready
in.d.valid := a.valid
in.d.bits := edge.AccessAck(a.bits, UInt(0))
in.d.bits.opcode := Mux(hasData, TLMessages.AccessAck, TLMessages.AccessAckData)
// Tie off unused channels
in.b.valid := Bool(false)
in.c.ready := Bool(true)
in.e.ready := Bool(true)
}
}