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