/*************************************************************************************** * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences * Copyright (c) 2020-2021 Peng Cheng Laboratory * * XiangShan is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * * See the Mulan PSL v2 for more details. ***************************************************************************************/ package device.standalone import chisel3._ import chisel3.util._ import chisel3.experimental.{annotate, ChiselAnnotation} import chisel3.experimental.dataview._ import freechips.rocketchip.diplomacy._ import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.devices.debug.DebugModuleKey import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.amba.axi4._ import freechips.rocketchip.tilelink._ import top.Generator import system.SoCParamsKey import sifive.enterprise.firrtl.NestedPrefixModulesAnnotation import scala.annotation.tailrec import xiangshan.XSTileKey import utils.VerilogAXI4Record trait HasMasterInterface { this: StandAloneDevice => def masterAddrWidth: Int protected val masternode = TLIdentityNode() // tilelink master io private val tlmaster = Option.when(useTL)(TLManagerNode(Seq( TLSlavePortParameters.v1( managers = Seq( TLSlaveParameters.v1( address = Seq(AddressSet(0, (BigInt(1) << masterAddrWidth) - 1)), regionType = RegionType.UNCACHED, supportsGet = TransferSizes(1, p(SoCParamsKey).L3BlockSize), supportsPutPartial = TransferSizes(1, p(SoCParamsKey).L3BlockSize), supportsPutFull = TransferSizes(1, p(SoCParamsKey).L3BlockSize), fifoId = Some(0) ) ), beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 ) ))) tlmaster.foreach(_ := masternode) val tlmasternode = tlmaster.map(tlmaster => InModuleBody(tlmaster.makeIOs())) // axi4 master io private val axi4master = Option.when(!useTL)(AXI4SlaveNode(Seq( AXI4SlavePortParameters( slaves = Seq( AXI4SlaveParameters( address = Seq(AddressSet(0, (BigInt(1) << masterAddrWidth) - 1)), regionType = RegionType.UNCACHED, supportsRead = TransferSizes(1, p(SoCParamsKey).L3BlockSize), supportsWrite = TransferSizes(1, p(SoCParamsKey).L3BlockSize), interleavedId = Some(0) ) ), beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 ) ))) axi4master.foreach( _ := AXI4Buffer() := AXI4Buffer() := AXI4Buffer() := AXI4IdIndexer(1) := AXI4UserYanker() := AXI4Deinterleaver(p(SoCParamsKey).L3BlockSize) := TLToAXI4() := TLSourceShrinker(64) := TLWidthWidget(p(SoCParamsKey).L3OuterBusWidth / 8) := TLBuffer.chainNode(2) := masternode ) val axi4masternode = axi4master.map(axi4master => InModuleBody { val axi4masternode = chisel3.IO(new VerilogAXI4Record(axi4master.in.head._1.params)) axi4masternode.viewAs[AXI4Bundle] <> axi4master.in.head._1 axi4masternode }) } abstract class StandAloneDevice ( val useTL: Boolean = false, val baseAddress: BigInt, val addrWidth: Int, val dataWidth: Int, val hartNum: Int )(implicit p: Parameters) extends LazyModule { def addressSet: AddressSet private val dummy = LazyModule(new TLError( params = DevNullParams( address = AddressSet(0, (BigInt(1) << addrWidth) - 1).subtract(addressSet), maxAtomic = 8, maxTransfer = 64 ), beatBytes = dataWidth / 8 )) protected val xbar = TLXbar() dummy.node := xbar // tilelink io private val tl = Option.when(useTL)(TLClientNode(Seq(TLMasterPortParameters.v1( Seq(TLMasterParameters.v1("tl", IdRange(0, 1))) )))) tl.foreach(xbar := _) val tlnode = tl.map(tl => InModuleBody(tl.makeIOs())) // axi4 io private val axi4 = Option.when(!useTL)(AXI4MasterNode(Seq(AXI4MasterPortParameters( Seq(AXI4MasterParameters("axi4", IdRange(0, 1))) )))) axi4.foreach( xbar := TLFIFOFixer() := AXI4ToTL() := AXI4UserYanker(Some(1)) := AXI4Fragmenter() := AXI4Buffer() := AXI4Buffer() := AXI4IdIndexer(1) := _ ) val axi4node = axi4.map(axi4 => InModuleBody { val axi4node = chisel3.IO(Flipped(new VerilogAXI4Record(axi4.out.head._1.params))) axi4node.viewAs[AXI4Bundle] <> axi4.out.head._1 axi4node }) lazy val module: LazyModuleImpLike = new StandAloneDeviceImp(this) } class StandAloneDeviceImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyModuleImp(outer) with RequireAsyncReset { p(SoCParamsKey).XSTopPrefix.foreach { prefix => val mod = this.toNamed annotate(new ChiselAnnotation { def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) }) } } class StandAloneDeviceRawImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyRawModuleImp(outer) { p(SoCParamsKey).XSTopPrefix.foreach { prefix => val mod = this.toNamed annotate(new ChiselAnnotation { def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) }) } } object ArgParser { def parse(args: Array[String], p: Parameters): (StandAloneDevice, Array[String]) = { var firrtlOpts = Array[String]() var module: String = "" var useTL: Boolean = false var baseAddress: BigInt = -1 var addrWidth: Int = -1 var dataWidth: Int = 64 @tailrec def nextOption(list: List[String]): Unit = { list match { case Nil => case "--standalone-device" :: value :: tail => module = value nextOption(tail) case "--use-tl" :: tail => useTL = true nextOption(tail) case "--use-axi4" :: tail => useTL = false nextOption(tail) case "--device-base-addr" :: value :: tail => baseAddress = value match { case s"0x$hex" => BigInt(hex, 16) case s"0X$hex" => BigInt(hex, 16) case _: String => BigInt(value) } nextOption(tail) case "--device-addr-width" :: value :: tail => addrWidth = value.toInt nextOption(tail) case "--device-data-width" :: value :: tail => dataWidth = value.toInt nextOption(tail) case option :: tail => // unknown option, maybe a firrtl option, skip firrtlOpts :+= option nextOption(tail) } } nextOption(args.toList) require(baseAddress >= 0, "baseAddress not specified correctly") require(addrWidth >= 0, "addrWidth not specified correctly") require(dataWidth >= 0, "dataWidth not specified correctly") val device: StandAloneDevice = module match { case "StandAloneCLINT" => DisableMonitors(p => LazyModule(new StandAloneCLINT( useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size )(p)))(p) case "StandAlonePLIC" => DisableMonitors(p => LazyModule(new StandAlonePLIC( useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size )(p)))(p) case "StandAloneDebugModule" => DisableMonitors(p => LazyModule(new StandAloneDebugModule( useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size )(p)))(p.alter((site, here, up) => { case DebugModuleKey => up(DebugModuleKey).map(_.copy(baseAddress = baseAddress)) })) case _: String => throw new IllegalArgumentException(s"$module not found") } (device, firrtlOpts) } } object Main extends App { val (config, secondaryOpts, firtoolOpts) = top.ArgParser.parse(args) val (device, firrtlOpts) = ArgParser.parse(secondaryOpts, config) Generator.execute(firrtlOpts, device.module, firtoolOpts) }