Skip to content

Latest commit

 

History

History
210 lines (162 loc) · 6.88 KB

Config.md

File metadata and controls

210 lines (162 loc) · 6.88 KB

Config

预备知识

​ 偏函数,在Scala中它是一个Trait, PartialFunction[A, B], 它接受一个A参数,返回一个B

val f: PartialFunction[Int, String] = {
    case 1 => "One",
    case 2 => "Two",
    case 3 => "Three",
    case _ => "Other"
}

概述

​ 在Rocket-chip等生成器中,可以通过配置Config文件来定制生成CPU,接下来将介绍其实现原理

Field

package freechips.rocketchip.config

abstract class Field[T] private(val default: Option[T])
{
    def this() = this(None)
    def this(default: T) = this(Some(default))
}

​ 我们在config这个子模块中定义了Field类,作为一个抽象类它无法实例化,但是它提供了两个方法,this放回一个为NoneOption,而this(default: T), 当以了一个内容为defaultOption

​ 这个类型可以将所有的类型全部加一层Option

View

abstract class View {
    final def apply[T](pname: Field[T]): T = apply(pname, this)
    final def apply[T](pname: Field[T], site: View): T = {
        val out = find(pname, site)
        require(out.isDefined, s"Key ${pname} is not defined in Parameters")
        out.get
    }
    final def lift[T](pname: Field[T]): Option[T] = lift(pname, this)
    final def lift[T](pname: Filed[T], site: View): Option[T] = find(pname, site)															.map(_.asInstanceOf[T])
    protected[config] def find[T](pname: Field[T], site: View): Option[T]
}

​ 这里find是一个抽象方法,我们需要在继承View后,apply中调用了find方法。

Parameters

abstract class Parameters extends View {
  final def ++ (x: Parameters): Parameters =
    new ChainParameters(this, x)
 
  final def alter(f: (View, View, View) => PartialFunction[Any,Any]): Parameters =
    Parameters(f) ++ this
 
  final def alterPartial(f: PartialFunction[Any,Any]): Parameters =
    Parameters((_,_,_) => f) ++ this
 
  final def alterMap(m: Map[Any,Any]): Parameters =
    new MapParameters(m) ++ this
 
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]): Option[T]
  protected[config] def find[T](pname: Field[T], site: View) = chain(site, new TerminalView, pname)
}
 
object Parameters {
  def empty: Parameters = new EmptyParameters
  def apply(f: (View, View, View) => PartialFunction[Any,Any]): Parameters = new PartialParameters(f)
}

private class TerminalView extends View {
  def find[T](pname: Field[T], site: View): Option[T] = pname.default
}
 
private class ChainView(head: Parameters, tail: View) extends View {
  def find[T](pname: Field[T], site: View) = head.chain(site, tail, pname)
}

Parameters继承了View,实现了find方法,但是方法也调用了chainchian中的site表示当前视图,tail表示了下一试图,pname则是要找的配置项。

Config

class Config(p: Parameters) extends Parameters {
    def this(f: (View, View, View)) => PartialFunction[Any, Any]) = this(Parameters(f))
    
    protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = p.chain(site, tail, pname) 
    override def toString = this.getClass.getSimpleName
    def toInstance = this
}

private class ChainParameters(x: Parameters, y: Parameters) extends Parameters {
  def chain[T](site: View, tail: View, pname: Field[T]) = x.chain(site, new ChainView(y, tail), pname)
}
 
private class EmptyParameters extends Parameters {
  def chain[T](site: View, tail: View, pname: Field[T]) = tail.find(pname, site)
}
 
private class PartialParameters(f: (View, View, View) => PartialFunction[Any,Any]) extends Parameters {
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = {
    val g = f(site, this, tail)
    if (g.isDefinedAt(pname)) Some(g.apply(pname).asInstanceOf[T]) else tail.find(pname, site)
  }
}
 
private class MapParameters(map: Map[Any, Any]) extends Parameters {
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = {
    val g = map.get(pname)
    if (g.isDefined) Some(g.get.asInstanceOf[T]) else tail.find(pname, site)
  }
}

​ 这里Config继承了Parameterschian中直接调用了p参数的chain方法。使用PartialParameters,它是一个私有类。它会调用传入的隐式参数方法。

实现

package mini

import chisel3.Module
import freechips.rocketchip.config.{Parameters, Config}
import junctions._

class MiniConfig extends Config((site, here, up)) => {
    case XLEN => 32,
    case Trace => true,
    case BuildALU => (p: Parameters) => Module(new ALUArea()(p))
    case BuildImmGen => (p: Parameters) => Module(new ImmGenWire()(p))
    case BuildBrCond => (p: Parameters) => Module(new BrCondArea()(p))
    case NWays => 1
    case NSets => 256
    case CacheBlockBytes => 4 * (here(XLEN) >> 3) 
    case NastiKey => new NastiParameters(
    	idBits = 5,
        dataBits = 64,
        addrBits = here(XLEN))
    )
}

实际使用的时候,可以先看顶层:

val params = (new MiniConfig).toInstance
val chirrtl = firrtl.Parser.parse(chisel3.Driver.emit(() => new Tile(params)))

​ 这里在Tile中传入了param参数,由于隐私参数的性质,这个参数可以不断向下传播。

class Tile(tileParams: Parameters) extends Module with TileBase {
    implicit val p = tileParams
    val io = IO(new TileIO)
    val core = Module(new Core)
    val icache = Module(new Cache)
    val dcache = Module(new Cache)
    val arb = Module(new MemArbiter)
    
    io.host <> core.io.host
    core.io.cache <> icache.io.cpu
    core.io.dcache <> dcache.io.cpu
    arb.io.icache <> icache.io.nasti
    arb.io.dcache <> dcache.io.nasti
    io.nasti <> arb.io.nasti
}

Tile模块把入参赋值给隐式参数p。之后传入接下来所有的模块。以Core模块为例

abstract trait CoreParams {
    implicit val p: Parameters
    val xlen = p(XLEN)
}

​ 这里p我们知道传入的是一个miniConfig, 有一个父类类型Parameter进行接受是合法的。接着我们调用了p(XLEN), 由于传入的XLEN是一个Field类型,这里会调用,Viewapply方法,

最终会调用:

final def apply[T](pname: Field[T], site: View): T = {
    val out = find(pname, site)
    require(out.isDefined, s"Key ${pname} is not defined in Parameters")
    out.get
}

这里的find又会调用之前介绍的PartialParameterschain方法:

protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = {
	val g = f(site, this, tail)
    if (g.isDefinedAt(pname)) Some(g.apply(pname).asInstanceOf[T])
    else tail.find(pname, site)
}

​ 之后就会跟我们的(site, here, tail) => {case...}进行匹配。