1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package device.standalone 18 19import chisel3._ 20import chisel3.util._ 21import chisel3.experimental.{annotate, ChiselAnnotation} 22import chisel3.experimental.dataview._ 23import freechips.rocketchip.diplomacy._ 24import org.chipsalliance.cde.config.Parameters 25import freechips.rocketchip.devices.debug.DebugModuleKey 26import freechips.rocketchip.devices.tilelink._ 27import freechips.rocketchip.amba.axi4._ 28import freechips.rocketchip.tilelink._ 29import top.Generator 30import system.SoCParamsKey 31import sifive.enterprise.firrtl.NestedPrefixModulesAnnotation 32import scala.annotation.tailrec 33import xiangshan.XSTileKey 34import utils.VerilogAXI4Record 35 36trait HasMasterInterface { this: StandAloneDevice => 37 38 def masterAddrWidth: Int 39 40 protected val masternode = TLIdentityNode() 41 // tilelink master io 42 private val tlmaster = Option.when(useTL)(TLManagerNode(Seq( 43 TLSlavePortParameters.v1( 44 managers = Seq( 45 TLSlaveParameters.v1( 46 address = Seq(AddressSet(0, (BigInt(1) << masterAddrWidth) - 1)), 47 regionType = RegionType.UNCACHED, 48 supportsGet = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 49 supportsPutPartial = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 50 supportsPutFull = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 51 fifoId = Some(0) 52 ) 53 ), 54 beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 55 ) 56 ))) 57 tlmaster.foreach(_ := masternode) 58 val tlmasternode = tlmaster.map(tlmaster => InModuleBody(tlmaster.makeIOs())) 59 60 // axi4 master io 61 private val axi4master = Option.when(!useTL)(AXI4SlaveNode(Seq( 62 AXI4SlavePortParameters( 63 slaves = Seq( 64 AXI4SlaveParameters( 65 address = Seq(AddressSet(0, (BigInt(1) << masterAddrWidth) - 1)), 66 regionType = RegionType.UNCACHED, 67 supportsRead = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 68 supportsWrite = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 69 interleavedId = Some(0) 70 ) 71 ), 72 beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 73 ) 74 ))) 75 axi4master.foreach( 76 _ := 77 AXI4Buffer() := 78 AXI4Buffer() := 79 AXI4Buffer() := 80 AXI4IdIndexer(1) := 81 AXI4UserYanker() := 82 AXI4Deinterleaver(p(SoCParamsKey).L3BlockSize) := 83 TLToAXI4() := 84 TLSourceShrinker(64) := 85 TLWidthWidget(p(SoCParamsKey).L3OuterBusWidth / 8) := 86 TLBuffer.chainNode(2) := 87 masternode 88 ) 89 val axi4masternode = axi4master.map(axi4master => InModuleBody { 90 val axi4masternode = chisel3.IO(new VerilogAXI4Record(axi4master.in.head._1.params)) 91 axi4masternode.viewAs[AXI4Bundle] <> axi4master.in.head._1 92 axi4masternode 93 }) 94} 95 96abstract class StandAloneDevice ( 97 val useTL: Boolean = false, 98 val baseAddress: BigInt, 99 val addrWidth: Int, 100 val dataWidth: Int, 101 val hartNum: Int 102)(implicit p: Parameters) extends LazyModule { 103 104 def addressSet: AddressSet 105 106 private val dummy = LazyModule(new TLError( 107 params = DevNullParams( 108 address = AddressSet(0, (BigInt(1) << addrWidth) - 1).subtract(addressSet), 109 maxAtomic = 8, 110 maxTransfer = 64 111 ), 112 beatBytes = dataWidth / 8 113 )) 114 protected val xbar = TLXbar() 115 dummy.node := xbar 116 117 // tilelink io 118 private val tl = Option.when(useTL)(TLClientNode(Seq(TLMasterPortParameters.v1( 119 Seq(TLMasterParameters.v1("tl", IdRange(0, 1))) 120 )))) 121 tl.foreach(xbar := _) 122 val tlnode = tl.map(tl => InModuleBody(tl.makeIOs())) 123 124 // axi4 io 125 private val axi4 = Option.when(!useTL)(AXI4MasterNode(Seq(AXI4MasterPortParameters( 126 Seq(AXI4MasterParameters("axi4", IdRange(0, 1))) 127 )))) 128 axi4.foreach( 129 xbar := 130 TLFIFOFixer() := 131 AXI4ToTL() := 132 AXI4UserYanker(Some(1)) := 133 AXI4Fragmenter() := 134 AXI4Buffer() := 135 AXI4Buffer() := 136 AXI4IdIndexer(1) := 137 _ 138 ) 139 val axi4node = axi4.map(axi4 => InModuleBody { 140 val axi4node = chisel3.IO(Flipped(new VerilogAXI4Record(axi4.out.head._1.params))) 141 axi4node.viewAs[AXI4Bundle] <> axi4.out.head._1 142 axi4node 143 }) 144 145 lazy val module: LazyModuleImpLike = new StandAloneDeviceImp(this) 146 147} 148 149class StandAloneDeviceImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyModuleImp(outer) with RequireAsyncReset { 150 p(SoCParamsKey).XSTopPrefix.foreach { prefix => 151 val mod = this.toNamed 152 annotate(new ChiselAnnotation { 153 def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) 154 }) 155 } 156} 157 158class StandAloneDeviceRawImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyRawModuleImp(outer) { 159 p(SoCParamsKey).XSTopPrefix.foreach { prefix => 160 val mod = this.toNamed 161 annotate(new ChiselAnnotation { 162 def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) 163 }) 164 } 165} 166 167object ArgParser { 168 def parse(args: Array[String], p: Parameters): (StandAloneDevice, Array[String]) = { 169 var firrtlOpts = Array[String]() 170 var module: String = "" 171 var useTL: Boolean = false 172 var baseAddress: BigInt = -1 173 var addrWidth: Int = -1 174 var dataWidth: Int = 64 175 @tailrec 176 def nextOption(list: List[String]): Unit = { 177 list match { 178 case Nil => 179 case "--standalone-device" :: value :: tail => 180 module = value 181 nextOption(tail) 182 case "--use-tl" :: tail => 183 useTL = true 184 nextOption(tail) 185 case "--use-axi4" :: tail => 186 useTL = false 187 nextOption(tail) 188 case "--device-base-addr" :: value :: tail => 189 baseAddress = value match { 190 case s"0x$hex" => BigInt(hex, 16) 191 case s"0X$hex" => BigInt(hex, 16) 192 case _: String => BigInt(value) 193 } 194 nextOption(tail) 195 case "--device-addr-width" :: value :: tail => 196 addrWidth = value.toInt 197 nextOption(tail) 198 case "--device-data-width" :: value :: tail => 199 dataWidth = value.toInt 200 nextOption(tail) 201 case option :: tail => 202 // unknown option, maybe a firrtl option, skip 203 firrtlOpts :+= option 204 nextOption(tail) 205 } 206 } 207 nextOption(args.toList) 208 require(baseAddress >= 0, "baseAddress not specified correctly") 209 require(addrWidth >= 0, "addrWidth not specified correctly") 210 require(dataWidth >= 0, "dataWidth not specified correctly") 211 val device: StandAloneDevice = module match { 212 case "StandAloneCLINT" => 213 DisableMonitors(p => LazyModule(new StandAloneCLINT( 214 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 215 )(p)))(p) 216 case "StandAlonePLIC" => 217 DisableMonitors(p => LazyModule(new StandAlonePLIC( 218 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 219 )(p)))(p) 220 case "StandAloneDebugModule" => 221 DisableMonitors(p => LazyModule(new StandAloneDebugModule( 222 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 223 )(p)))(p.alter((site, here, up) => { 224 case DebugModuleKey => up(DebugModuleKey).map(_.copy(baseAddress = baseAddress)) 225 })) 226 case _: String => throw new IllegalArgumentException(s"$module not found") 227 } 228 (device, firrtlOpts) 229 } 230} 231 232object Main extends App { 233 val (config, secondaryOpts, firtoolOpts) = top.ArgParser.parse(args) 234 val (device, firrtlOpts) = ArgParser.parse(secondaryOpts, config) 235 236 Generator.execute(firrtlOpts, device.module, firtoolOpts) 237} 238