xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision 8891a219bbc84f568e1d134854d8d5ed86d6d560)
1c6d43980SLemover/***************************************************************************************
2c6d43980SLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3f320e0f0SYinan Xu* Copyright (c) 2020-2021 Peng Cheng Laboratory
4c6d43980SLemover*
5c6d43980SLemover* XiangShan is licensed under Mulan PSL v2.
6c6d43980SLemover* You can use this software according to the terms and conditions of the Mulan PSL v2.
7c6d43980SLemover* You may obtain a copy of Mulan PSL v2 at:
8c6d43980SLemover*          http://license.coscl.org.cn/MulanPSL2
9c6d43980SLemover*
10c6d43980SLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11c6d43980SLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12c6d43980SLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13c6d43980SLemover*
14c6d43980SLemover* See the Mulan PSL v2 for more details.
15c6d43980SLemover***************************************************************************************/
16c6d43980SLemover
178b16d276SZihao Yupackage device
188b16d276SZihao Yu
198b16d276SZihao Yuimport chisel3._
208b16d276SZihao Yuimport chisel3.util._
21*8891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
22510ae4eeSJiuyang Liuimport chisel3.experimental.ExtModule
23226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar}
24226300c2Slinjiaweiimport freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType}
258b16d276SZihao Yuimport utils._
263c02ee8fSwakafaimport utility._
278b16d276SZihao Yu
288b16d276SZihao Yutrait HasVGAConst {
298b16d276SZihao Yu  val ScreenW = 800
308b16d276SZihao Yu  val ScreenH = 600
318b16d276SZihao Yu
328b16d276SZihao Yu  val HFrontPorch = 56
338b16d276SZihao Yu  val HActive = HFrontPorch + 120
348b16d276SZihao Yu  val HBackPorch = HActive + ScreenW
358b16d276SZihao Yu  val HTotal = HBackPorch + 64
368b16d276SZihao Yu  val VFrontPorch = 37
378b16d276SZihao Yu  val VActive = VFrontPorch + 6
388b16d276SZihao Yu  val VBackPorch = VActive + ScreenH
398b16d276SZihao Yu  val VTotal = VBackPorch + 23
40ec9268f7SZihao Yu}
418b16d276SZihao Yu
42ec9268f7SZihao Yutrait HasHDMIConst {
43ec9268f7SZihao Yu  val ScreenW = 800
44ec9268f7SZihao Yu  val ScreenH = 600
45ec9268f7SZihao Yu
46ec9268f7SZihao Yu  val HFrontPorch = 40
47ec9268f7SZihao Yu  val HActive = HFrontPorch + 128
48ec9268f7SZihao Yu  val HBackPorch = HActive + ScreenW
49ec9268f7SZihao Yu  val HTotal = HBackPorch + 88
50ec9268f7SZihao Yu  val VFrontPorch = 1
51ec9268f7SZihao Yu  val VActive = VFrontPorch + 4
52ec9268f7SZihao Yu  val VBackPorch = VActive + ScreenH
53ec9268f7SZihao Yu  val VTotal = VBackPorch + 23
54ec9268f7SZihao Yu}
55ec9268f7SZihao Yu
56ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst {
578b16d276SZihao Yu  val FBWidth = ScreenW / 2
588b16d276SZihao Yu  val FBHeight = ScreenH / 2
598b16d276SZihao Yu  val FBPixels = FBWidth * FBHeight
608b16d276SZihao Yu}
618b16d276SZihao Yu
628b16d276SZihao Yuclass VGABundle extends Bundle {
63ec9268f7SZihao Yu  val rgb = Output(UInt(24.W))
648b16d276SZihao Yu  val hsync = Output(Bool())
658b16d276SZihao Yu  val vsync = Output(Bool())
66ec9268f7SZihao Yu  val valid = Output(Bool())
678b16d276SZihao Yu}
688b16d276SZihao Yu
69096a786aSZihao Yuclass VGACtrlBundle extends Bundle {
70096a786aSZihao Yu  val sync = Output(Bool())
71096a786aSZihao Yu}
72096a786aSZihao Yu
73226300c2Slinjiaweiclass VGACtrl
74226300c2Slinjiawei(
75a2e9bde6SAllen  address: Seq[AddressSet]
76226300c2Slinjiawei)(implicit p: Parameters)
77226300c2Slinjiawei  extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter {
78226300c2Slinjiawei  override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) {
79226300c2Slinjiawei
808b16d276SZihao Yu    val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
81935edac4STang Haojin    val sync = in.aw.fire
82096a786aSZihao Yu
83096a786aSZihao Yu    val mapping = Map(
84096a786aSZihao Yu      RegMap(0x0, fbSizeReg, RegMap.Unwritable),
85096a786aSZihao Yu      RegMap(0x4, sync, RegMap.Unwritable)
86096a786aSZihao Yu    )
87096a786aSZihao Yu
88096a786aSZihao Yu    RegMap.generate(mapping, raddr(3, 0), in.r.bits.data,
89935edac4STang Haojin      waddr(3, 0), in.w.fire, in.w.bits.data, MaskExpand(in.w.bits.strb))
90096a786aSZihao Yu
91096a786aSZihao Yu    io.extra.get.sync := sync
928b16d276SZihao Yu  }
93226300c2Slinjiawei}
948b16d276SZihao Yu
95510ae4eeSJiuyang Liuclass FBHelper extends ExtModule with HasExtModuleInline {
96510ae4eeSJiuyang Liu  val clk = IO(Input(Clock()))
97510ae4eeSJiuyang Liu  val valid = IO(Input(Bool()))
98510ae4eeSJiuyang Liu  val pixel = IO(Input(UInt(32.W)))
99510ae4eeSJiuyang Liu  val sync = IO(Input(Bool()))
10043002b01SZihao Yu
10143002b01SZihao Yu  setInline("FBHelper.v",
10243002b01SZihao Yu    s"""
10343002b01SZihao Yu       |import "DPI-C" function void put_pixel(input int pixel);
10443002b01SZihao Yu       |import "DPI-C" function void vmem_sync();
10543002b01SZihao Yu       |
10643002b01SZihao Yu       |module FBHelper (
10743002b01SZihao Yu       |  input clk,
10843002b01SZihao Yu       |  input valid,
10943002b01SZihao Yu       |  input [31:0] pixel,
11043002b01SZihao Yu       |  input sync
11143002b01SZihao Yu       |);
11243002b01SZihao Yu       |
11343002b01SZihao Yu       |  always@(posedge clk) begin
11443002b01SZihao Yu       |    if (valid) put_pixel(pixel);
11543002b01SZihao Yu       |    if (sync) vmem_sync();
11643002b01SZihao Yu       |  end
11743002b01SZihao Yu       |
11843002b01SZihao Yu       |endmodule
11943002b01SZihao Yu     """.stripMargin)
12043002b01SZihao Yu}
12143002b01SZihao Yu
122226300c2Slinjiaweiclass AXI4VGA
123226300c2Slinjiawei(
124226300c2Slinjiawei  sim: Boolean = false,
125a2e9bde6SAllen  fbAddress: Seq[AddressSet],
126a2e9bde6SAllen  ctrlAddress: Seq[AddressSet]
127226300c2Slinjiawei)(implicit p: Parameters)
128226300c2Slinjiawei  extends LazyModule with HasVGAParameter {
129226300c2Slinjiawei
130226300c2Slinjiawei
1316f1f3ac7Slinjiawei  private val fb = LazyModule(new AXI4RAM(
1326f1f3ac7Slinjiawei    fbAddress,
1336f1f3ac7Slinjiawei    memByte= FBPixels * 4,
1346f1f3ac7Slinjiawei    sim,
1356f1f3ac7Slinjiawei    executable = false
1366f1f3ac7Slinjiawei  ))
137226300c2Slinjiawei  private val ctrl = LazyModule(new VGACtrl(ctrlAddress))
138226300c2Slinjiawei
139226300c2Slinjiawei  val node = AXI4IdentityNode()
140226300c2Slinjiawei
141226300c2Slinjiawei  fb.node := node
142226300c2Slinjiawei  ctrl.node := node
143226300c2Slinjiawei
144226300c2Slinjiawei  lazy val module = new LazyModuleImp(this) {
145226300c2Slinjiawei
146226300c2Slinjiawei    val io = IO(new Bundle() {
1478b16d276SZihao Yu      val vga = new VGABundle
1488b16d276SZihao Yu    })
1498b16d276SZihao Yu
150226300c2Slinjiawei    val out_fb = node.out.head._1
151226300c2Slinjiawei    val out_ctrl = node.out.last._1
152226300c2Slinjiawei    val in_fb = node.in.head._1
153226300c2Slinjiawei    val in_ctrl = node.in.last._1
154226300c2Slinjiawei
155226300c2Slinjiawei    in_fb.ar.ready := true.B
156226300c2Slinjiawei    in_fb.r.bits.data := 0.U
157226300c2Slinjiawei    in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY
158935edac4STang Haojin    in_fb.r.valid := BoolStopWatch(in_fb.ar.fire, in_fb.r.fire, startHighPriority = true)
1598b16d276SZihao Yu
1608b16d276SZihao Yu    def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
1618b16d276SZihao Yu
1628b16d276SZihao Yu    val (hCounter, hFinish) = Counter(true.B, HTotal)
1638b16d276SZihao Yu    val (vCounter, vFinish) = Counter(hFinish, VTotal)
1648b16d276SZihao Yu    io.vga.hsync := hCounter >= HFrontPorch.U
1658b16d276SZihao Yu    io.vga.vsync := vCounter >= VFrontPorch.U
1668b16d276SZihao Yu
1678b16d276SZihao Yu    val hInRange = inRange(hCounter, HActive, HBackPorch)
1688b16d276SZihao Yu    val vInRange = inRange(vCounter, VActive, VBackPorch)
169ec9268f7SZihao Yu    io.vga.valid := hInRange && vInRange
1708b16d276SZihao Yu
1718b16d276SZihao Yu    val hCounterIsOdd = hCounter(0)
1729904078bSZihao Yu    val hCounterIs2 = hCounter(1, 0) === 2.U
1738b16d276SZihao Yu    val vCounterIsOdd = vCounter(0)
1749904078bSZihao Yu    // there is 2 cycle latency to read block memory,
1759904078bSZihao Yu    // so we should issue the read request 2 cycle eariler
1768b16d276SZihao Yu    val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
1778b16d276SZihao Yu    val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
1788b16d276SZihao Yu    val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1
1798b16d276SZihao Yu
1808b16d276SZihao Yu    //   each pixel is 4 bytes
181226300c2Slinjiawei    out_fb.ar.bits.prot := 0.U
182226300c2Slinjiawei    out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
183226300c2Slinjiawei    out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2
1848b16d276SZihao Yu
185226300c2Slinjiawei    out_fb.r.ready := true.B
186935edac4STang Haojin    val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire)
1879904078bSZihao Yu    val color = Mux(hCounter(1), data(63, 32), data(31, 0))
188ec9268f7SZihao Yu    io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
18943002b01SZihao Yu
19043002b01SZihao Yu    if (sim) {
19143002b01SZihao Yu      val fbHelper = Module(new FBHelper)
192510ae4eeSJiuyang Liu      fbHelper.clk := clock
193510ae4eeSJiuyang Liu      fbHelper.valid := io.vga.valid
194510ae4eeSJiuyang Liu      fbHelper.pixel := color
195510ae4eeSJiuyang Liu      fbHelper.sync := ctrl.module.io.extra.get.sync
19643002b01SZihao Yu    }
197226300c2Slinjiawei
198226300c2Slinjiawei  }
199226300c2Slinjiawei
200226300c2Slinjiawei  //  val AXIidBits = 2
201226300c2Slinjiawei  //  val io = IO(new Bundle {
202226300c2Slinjiawei  //    val in = new Bundle {
203226300c2Slinjiawei  //      val fb = Flipped(new AXI4Lite)
204226300c2Slinjiawei  //      val ctrl = Flipped(new AXI4Lite)
205226300c2Slinjiawei  //    }
206226300c2Slinjiawei  //    val vga = new VGABundle
207226300c2Slinjiawei  //  })
208226300c2Slinjiawei  //
209226300c2Slinjiawei  //  val ctrl = Module(new VGACtrl)
210226300c2Slinjiawei  //  io.in.ctrl <> ctrl.io.in
211226300c2Slinjiawei  //  val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4))
212226300c2Slinjiawei  //  // writable by axi4lite
213226300c2Slinjiawei  //  // but it only readable by the internel controller
214226300c2Slinjiawei  //  fb.io.in.aw <> io.in.fb.aw
215226300c2Slinjiawei  //  fb.io.in.w <> io.in.fb.w
216226300c2Slinjiawei  //  io.in.fb.b <> fb.io.in.b
217226300c2Slinjiawei  //  io.in.fb.ar.ready := true.B
218226300c2Slinjiawei  //  io.in.fb.r.bits.data := 0.U
219226300c2Slinjiawei  //  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
220935edac4STang Haojin  //  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire, io.in.fb.r.fire, startHighPriority = true)
221226300c2Slinjiawei  //
222226300c2Slinjiawei  //  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
223226300c2Slinjiawei  //
224226300c2Slinjiawei  //  val (hCounter, hFinish) = Counter(true.B, HTotal)
225226300c2Slinjiawei  //  val (vCounter, vFinish) = Counter(hFinish, VTotal)
226226300c2Slinjiawei  //
227226300c2Slinjiawei  //  io.vga.hsync := hCounter >= HFrontPorch.U
228226300c2Slinjiawei  //  io.vga.vsync := vCounter >= VFrontPorch.U
229226300c2Slinjiawei  //
230226300c2Slinjiawei  //  val hInRange = inRange(hCounter, HActive, HBackPorch)
231226300c2Slinjiawei  //  val vInRange = inRange(vCounter, VActive, VBackPorch)
232226300c2Slinjiawei  //  io.vga.valid := hInRange && vInRange
233226300c2Slinjiawei  //
234226300c2Slinjiawei  //  val hCounterIsOdd = hCounter(0)
235226300c2Slinjiawei  //  val hCounterIs2 = hCounter(1,0) === 2.U
236226300c2Slinjiawei  //  val vCounterIsOdd = vCounter(0)
237226300c2Slinjiawei  //  // there is 2 cycle latency to read block memory,
238226300c2Slinjiawei  //  // so we should issue the read request 2 cycle eariler
239226300c2Slinjiawei  //  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
240226300c2Slinjiawei  //  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
241226300c2Slinjiawei  //  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
242226300c2Slinjiawei  //
243226300c2Slinjiawei  //  // each pixel is 4 bytes
244226300c2Slinjiawei  //  fb.io.in.ar.bits.prot := 0.U
245226300c2Slinjiawei  //  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
246226300c2Slinjiawei  //  fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2
247226300c2Slinjiawei  //
248226300c2Slinjiawei  //  fb.io.in.r.ready := true.B
249935edac4STang Haojin  //  val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire)
250226300c2Slinjiawei  //  val color = Mux(hCounter(1), data(63, 32), data(31, 0))
251226300c2Slinjiawei  //  io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
252226300c2Slinjiawei  //
253226300c2Slinjiawei  //  if (sim) {
254226300c2Slinjiawei  //    val fbHelper = Module(new FBHelper)
255226300c2Slinjiawei  //    fbHelper.io.clk := clock
256226300c2Slinjiawei  //    fbHelper.io.valid := io.vga.valid
257226300c2Slinjiawei  //    fbHelper.io.pixel := color
258226300c2Slinjiawei  //    fbHelper.io.sync := ctrl.io.extra.get.sync
259226300c2Slinjiawei  //  }
2608b16d276SZihao Yu}
261