blob: cb03f206bab7d48a23c2fc7e13f32fba27baa04c [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package kelvin
import chisel3._
import chisel3.util._
import scala.collection.mutable.StringBuilder
object MemoryRegionType extends ChiselEnum {
val IMEM = Value
val DMEM = Value
val Peripheral = Value
val External = Value
}
class MemoryRegion(
val memStart: Int,
val memSize: Int,
val memType: MemoryRegionType.Type,
) {
def contains(addr: UInt): Bool = {
val addrWidth = addr.getWidth.W
(addr >= memStart.U(addrWidth)) && (addr < memStart.U(addrWidth) + memSize.U(addrWidth))
}
}
object Parameters {
def apply(): Parameters = {
return new Parameters()
}
def apply(m: Seq[MemoryRegion]): Parameters = {
return new Parameters(m)
}
}
class Parameters(var m: Seq[MemoryRegion] = Seq(), val hartId: Int = 0) {
case object Core {
val tiny = 0
val little = 1
val big = 2
}
// Vector Length (register-file and compute).
// 128 = faster builds, but not production.
val vectorBits = sys.env.get("KELVIN_SIMD").getOrElse("256").toInt
assert(vectorBits == 512 || vectorBits == 256 || vectorBits == 128)
val core = vectorBits match {
case 128 => Core.tiny
case 256 => Core.little
case 512 => Core.big
}
// Machine.
val programCounterBits = 32
val instructionBits = 32
val instructionLanes = 4
val vectorCountBits = log2Ceil(vectorBits / 8) + 1 + 2 // +2 stripmine
// Enable Vector
var enableVector = true
val vectorAluCount = 2
val vectorReadPorts = (vectorAluCount * 3) + 1
val vectorWritePorts = 6
val vectorWhintPorts = 4
val vectorScalarPorts = 2
// Vector queue.
val vectorFifoDepth = 16
// Enable extra logic for verification purposes.
var enableVerification = false
// Enable RVV. This differs from "Vector" in that it conforms to the RVV1.0
// spec instead of the Kelvin Custom vector ISA.
var enableRvv = false
val rvvVlen = 128
def rvvVlenb: Int = { rvvVlen / 8 }
// Dispatch unit
var enableDispatchV2 = false
def useDispatchV2: Boolean = { enableRvv || enableDispatchV2 }
def useRetirementBuffer: Boolean = { useDispatchV2 && enableVerification }
// Scalar Floating point
var enableFloat = false
// Use the Div/Sqrt module from PULP instead of E906.
// It is smaller, but has small rounding errors.
val floatPulpDivsqrt = 0
// Retirement buffer
val floatRegfileBaseAddr = 32
val rvvRegfileBaseAddr = 64
val rvvRegCount = 32
val retirementBufferSize = 8
def retirementBufferIdxWidth: Int = {
val scalarRegCount = 32
val floatRegCount = (if (enableFloat) { 32 } else { 0 })
log2Ceil(scalarRegCount + floatRegCount + rvvRegCount + 1)
}
// L0ICache Fetch unit.
var enableFetchL0 = true
val fetchCacheBytes = 1024
// Scalar Core Fetch bus.
val fetchAddrBits = 32 // do not change
var fetchDataBits = 256 // do not change
def fetchInstrSlots: Int = {
assert(fetchDataBits % 32 == 0)
assert(instructionBits % 32 == 0)
assert(fetchDataBits % instructionBits == 0)
fetchDataBits / instructionBits
}
// Scalar Core Load Store Unit bus.
val lsuAddrBits = 32 // do not change
var lsuDataBits = vectorBits
def lsuDataBytes: Int = { lsuDataBits / 8 }
val lsuDelayPipelineLen = 1
def dbusSize: Int = { log2Ceil(lsuDataBits / 8) + 1 }
def useLsuV2: Boolean = { enableRvv }
var enableDebug = false
def useDebugModule: Boolean = { useDispatchV2 && enableDebug }
// TCM Size Configuration
var tcmHighmem = false
// [External] Core AXI interface.
val axiSysIdBits = 7
val axiSysAddrBits = 32
def axiSysDataBits: Int = { lsuDataBits }
// [Internal] L1ICache interface.
val l1islots = 256
val l1iassoc = 4
val axi0IdBits = 4 // (1x banks, 4 bits unused)
val axi0AddrBits = 32
def axi0DataBits: Int = { fetchDataBits }
// [Internal] L1DCache interface.
val l1dslots = 256 // (x2 banks)
val axi1IdBits = 4 // (x2 banks, 3 bits unused)
val axi1AddrBits = 32
def axi1DataBits: Int = { lsuDataBits } /* axiSysDataBits */ /* vectorBits */
// [Internal] TCM[Vector,Scalar] interface.
val axi2IdBits = 6
val axi2AddrBits = 32
def axi2DataBits: Int = { lsuDataBits } // vectorBits
def axi2DataBytes: Int = { axi2DataBits / 8 }
// If set, itcmMemoryFile should contain a path to a Verilog mem file.
// NB: Only used by CoreAxi
val itcmMemoryFile = ""
val csrInCount = 13
val csrOutCount = 8
}
import scala.reflect.runtime.{universe => ru}
object EmitParametersHeader {
def apply(p: Parameters): String = {
val mirror = ru.runtimeMirror(ru.getClass.getClassLoader)
val instanceMirror = mirror.reflect(p)
val symbol = instanceMirror.symbol
val typeSym = symbol.toType
val fields = typeSym.decls.collect {
case t: (ru.TermSymbol @unchecked) if t.isVal || t.isVar => t
}
var builder = new StringBuilder()
builder = builder.append("#ifndef KELVIN_PARAMETERS_H_\n")
builder = builder.append("#define KELVIN_PARAMETERS_H_\n")
builder = builder.append("\n")
builder = builder.append("#include <stdbool.h>\n")
builder = builder.append("\n")
fields.foreach { x =>
val fieldMirror = instanceMirror.reflectField(x.asTerm)
val fieldType = x.asTerm.typeSignature
val value = fieldMirror.get
val ctype = fieldType match {
case t if t =:= ru.typeOf[Int] => Some("int")
case t if t =:= ru.typeOf[Boolean] => Some("bool")
case _ => None
}
if (ctype != None) {
builder = builder.append(s"#define KP_${x.name} ${value}\n")
}
}
// TODO(atv): See if we can improve the reflection above to execute
// the methods for our dynamic parameters.
builder = builder.append(s"#define KP_dbusSize ${p.dbusSize}\n")
builder = builder.append(s"#define KP_useDispatchV2 ${p.useDispatchV2}\n")
builder = builder.append(s"#define KP_useRetirementBuffer ${p.useRetirementBuffer}\n")
builder = builder.append(s"#define KP_retirementBufferIdxWidth ${p.retirementBufferIdxWidth}\n")
builder = builder.append(s"#define KP_useDebugModule ${p.useDebugModule}\n")
builder = builder.append("#endif\n")
builder.result()
}
}