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