xref: /XiangShan/src/main/scala/device/standalone/StandAloneDevice.scala (revision b03c55a5df5dc8793cb44b42dd60141566e57e78)
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