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 protected val masternode = TLIdentityNode() 39 // tilelink master io 40 private val tlmaster = Option.when(useTL)(TLManagerNode(Seq( 41 TLSlavePortParameters.v1( 42 managers = Seq( 43 TLSlaveParameters.v1( 44 address = Seq(AddressSet(0, (BigInt(1) << addrWidth) - 1)), 45 regionType = RegionType.UNCACHED, 46 supportsGet = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 47 supportsPutPartial = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 48 supportsPutFull = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 49 fifoId = Some(0) 50 ) 51 ), 52 beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 53 ) 54 ))) 55 tlmaster.foreach(_ := masternode) 56 val tlmasternode = tlmaster.map(tlmaster => InModuleBody(tlmaster.makeIOs())) 57 58 // axi4 master io 59 private val axi4master = Option.when(!useTL)(AXI4SlaveNode(Seq( 60 AXI4SlavePortParameters( 61 slaves = Seq( 62 AXI4SlaveParameters( 63 address = Seq(AddressSet(0, (BigInt(1) << addrWidth) - 1)), 64 regionType = RegionType.UNCACHED, 65 supportsRead = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 66 supportsWrite = TransferSizes(1, p(SoCParamsKey).L3BlockSize), 67 interleavedId = Some(0) 68 ) 69 ), 70 beatBytes = p(SoCParamsKey).L3OuterBusWidth / 8 71 ) 72 ))) 73 axi4master.foreach( 74 _ := 75 AXI4Buffer() := 76 AXI4Buffer() := 77 AXI4Buffer() := 78 AXI4IdIndexer(1) := 79 AXI4UserYanker() := 80 AXI4Deinterleaver(p(SoCParamsKey).L3BlockSize) := 81 TLToAXI4() := 82 TLSourceShrinker(64) := 83 TLWidthWidget(p(SoCParamsKey).L3OuterBusWidth / 8) := 84 TLBuffer.chainNode(2) := 85 masternode 86 ) 87 val axi4masternode = axi4master.map(axi4master => InModuleBody { 88 val axi4masternode = chisel3.IO(new VerilogAXI4Record(axi4master.in.head._1.params)) 89 axi4masternode.viewAs[AXI4Bundle] <> axi4master.in.head._1 90 axi4masternode 91 }) 92} 93 94abstract class StandAloneDevice ( 95 val useTL: Boolean = false, 96 val baseAddress: BigInt, 97 val addrWidth: Int, 98 val dataWidth: Int, 99 val hartNum: Int 100)(implicit p: Parameters) extends LazyModule { 101 102 def addressSet: AddressSet 103 104 private val dummy = LazyModule(new TLError( 105 params = DevNullParams( 106 address = AddressSet(0, (BigInt(1) << addrWidth) - 1).subtract(addressSet), 107 maxAtomic = 8, 108 maxTransfer = 64 109 ), 110 beatBytes = dataWidth / 8 111 )) 112 protected val xbar = TLXbar() 113 dummy.node := xbar 114 115 // tilelink io 116 private val tl = Option.when(useTL)(TLClientNode(Seq(TLMasterPortParameters.v1( 117 Seq(TLMasterParameters.v1("tl", IdRange(0, 1))) 118 )))) 119 tl.foreach(xbar := _) 120 val tlnode = tl.map(tl => InModuleBody(tl.makeIOs())) 121 122 // axi4 io 123 private val axi4 = Option.when(!useTL)(AXI4MasterNode(Seq(AXI4MasterPortParameters( 124 Seq(AXI4MasterParameters("axi4", IdRange(0, 1))) 125 )))) 126 axi4.foreach( 127 xbar := 128 TLFIFOFixer() := 129 AXI4ToTL() := 130 AXI4UserYanker(Some(1)) := 131 AXI4Fragmenter() := 132 AXI4Buffer() := 133 AXI4Buffer() := 134 AXI4IdIndexer(1) := 135 _ 136 ) 137 val axi4node = axi4.map(axi4 => InModuleBody { 138 val axi4node = chisel3.IO(Flipped(new VerilogAXI4Record(axi4.out.head._1.params))) 139 axi4node.viewAs[AXI4Bundle] <> axi4.out.head._1 140 axi4node 141 }) 142 143 lazy val module: LazyModuleImpLike = new StandAloneDeviceImp(this) 144 145} 146 147class StandAloneDeviceImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyModuleImp(outer) with RequireAsyncReset { 148 p(SoCParamsKey).XSTopPrefix.foreach { prefix => 149 val mod = this.toNamed 150 annotate(new ChiselAnnotation { 151 def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) 152 }) 153 } 154} 155 156class StandAloneDeviceRawImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyRawModuleImp(outer) { 157 p(SoCParamsKey).XSTopPrefix.foreach { prefix => 158 val mod = this.toNamed 159 annotate(new ChiselAnnotation { 160 def toFirrtl = NestedPrefixModulesAnnotation(mod, prefix, true) 161 }) 162 } 163} 164 165object ArgParser { 166 def parse(args: Array[String], p: Parameters): (StandAloneDevice, Array[String]) = { 167 var firrtlOpts = Array[String]() 168 var module: String = "" 169 var useTL: Boolean = false 170 var baseAddress: BigInt = -1 171 var addrWidth: Int = -1 172 var dataWidth: Int = 64 173 @tailrec 174 def nextOption(list: List[String]): Unit = { 175 list match { 176 case Nil => 177 case "--standalone-device" :: value :: tail => 178 module = value 179 nextOption(tail) 180 case "--use-tl" :: tail => 181 useTL = true 182 nextOption(tail) 183 case "--use-axi4" :: tail => 184 useTL = false 185 nextOption(tail) 186 case "--device-base-addr" :: value :: tail => 187 baseAddress = value match { 188 case s"0x$hex" => BigInt(hex, 16) 189 case s"0X$hex" => BigInt(hex, 16) 190 case _: String => BigInt(value) 191 } 192 nextOption(tail) 193 case "--device-addr-width" :: value :: tail => 194 addrWidth = value.toInt 195 nextOption(tail) 196 case "--device-data-width" :: value :: tail => 197 dataWidth = value.toInt 198 nextOption(tail) 199 case option :: tail => 200 // unknown option, maybe a firrtl option, skip 201 firrtlOpts :+= option 202 nextOption(tail) 203 } 204 } 205 nextOption(args.toList) 206 require(baseAddress >= 0, "baseAddress not specified correctly") 207 require(addrWidth >= 0, "addrWidth not specified correctly") 208 require(dataWidth >= 0, "dataWidth not specified correctly") 209 val device: StandAloneDevice = module match { 210 case "StandAloneCLINT" => 211 DisableMonitors(p => LazyModule(new StandAloneCLINT( 212 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 213 )(p)))(p) 214 case "StandAlonePLIC" => 215 DisableMonitors(p => LazyModule(new StandAlonePLIC( 216 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 217 )(p)))(p) 218 case "StandAloneDebugModule" => 219 DisableMonitors(p => LazyModule(new StandAloneDebugModule( 220 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 221 )(p)))(p.alter((site, here, up) => { 222 case DebugModuleKey => up(DebugModuleKey).map(_.copy(baseAddress = baseAddress)) 223 })) 224 case _: String => throw new IllegalArgumentException(s"$module not found") 225 } 226 (device, firrtlOpts) 227 } 228} 229 230object Main extends App { 231 val (config, secondaryOpts, firtoolOpts) = top.ArgParser.parse(args) 232 val (device, firrtlOpts) = ArgParser.parse(secondaryOpts, config) 233 234 Generator.execute(firrtlOpts, device.module, firtoolOpts) 235} 236