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