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: StandAloneDeviceImp = new StandAloneDeviceImp(this) 143 144} 145 146class StandAloneDeviceImp(outer: StandAloneDevice)(implicit p: Parameters) extends LazyModuleImp(outer) { 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 155object ArgParser { 156 def parse(args: Array[String], p: Parameters): (StandAloneDevice, Array[String]) = { 157 var firrtlOpts = Array[String]() 158 var module: String = "" 159 var useTL: Boolean = false 160 var baseAddress: BigInt = -1 161 var addrWidth: Int = -1 162 var dataWidth: Int = 64 163 @tailrec 164 def nextOption(list: List[String]): Unit = { 165 list match { 166 case Nil => 167 case "--standalone-device" :: value :: tail => 168 module = value 169 nextOption(tail) 170 case "--use-tl" :: tail => 171 useTL = true 172 nextOption(tail) 173 case "--use-axi4" :: tail => 174 useTL = false 175 nextOption(tail) 176 case "--device-base-addr" :: value :: tail => 177 baseAddress = value match { 178 case s"0x$hex" => BigInt(hex, 16) 179 case s"0X$hex" => BigInt(hex, 16) 180 case _: String => BigInt(value) 181 } 182 nextOption(tail) 183 case "--device-addr-width" :: value :: tail => 184 addrWidth = value.toInt 185 nextOption(tail) 186 case "--device-data-width" :: value :: tail => 187 dataWidth = value.toInt 188 nextOption(tail) 189 case option :: tail => 190 // unknown option, maybe a firrtl option, skip 191 firrtlOpts :+= option 192 nextOption(tail) 193 } 194 } 195 nextOption(args.toList) 196 require(baseAddress >= 0, "baseAddress not specified correctly") 197 require(addrWidth >= 0, "addrWidth not specified correctly") 198 require(dataWidth >= 0, "dataWidth not specified correctly") 199 val device: StandAloneDevice = module match { 200 case "StandAloneCLINT" => 201 DisableMonitors(p => LazyModule(new StandAloneCLINT( 202 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 203 )(p)))(p) 204 case "StandAlonePLIC" => 205 DisableMonitors(p => LazyModule(new StandAlonePLIC( 206 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 207 )(p)))(p) 208 case "StandAloneDebugModule" => 209 DisableMonitors(p => LazyModule(new StandAloneDebugModule( 210 useTL, baseAddress, addrWidth, dataWidth, p(XSTileKey).size 211 )(p)))(p) 212 case _: String => throw new IllegalArgumentException(s"$module not found") 213 } 214 (device, firrtlOpts) 215 } 216} 217 218object Main extends App { 219 val (config, secondaryOpts, firtoolOpts) = top.ArgParser.parse(args) 220 val (device, firrtlOpts) = ArgParser.parse(secondaryOpts, config) 221 222 Generator.execute(firrtlOpts, device.module, firtoolOpts) 223} 224