xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision 226300c2ef92410b97429544048fc8cd716e5303)
18b16d276SZihao Yupackage device
28b16d276SZihao Yu
38b16d276SZihao Yuimport chisel3._
48b16d276SZihao Yuimport chisel3.util._
5*226300c2Slinjiaweiimport chipsalliance.rocketchip.config.Parameters
6*226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar}
7*226300c2Slinjiaweiimport freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType}
88b16d276SZihao Yuimport utils._
98b16d276SZihao Yu
108b16d276SZihao Yutrait HasVGAConst {
118b16d276SZihao Yu  val ScreenW = 800
128b16d276SZihao Yu  val ScreenH = 600
138b16d276SZihao Yu
148b16d276SZihao Yu  val HFrontPorch = 56
158b16d276SZihao Yu  val HActive = HFrontPorch + 120
168b16d276SZihao Yu  val HBackPorch = HActive + ScreenW
178b16d276SZihao Yu  val HTotal = HBackPorch + 64
188b16d276SZihao Yu  val VFrontPorch = 37
198b16d276SZihao Yu  val VActive = VFrontPorch + 6
208b16d276SZihao Yu  val VBackPorch = VActive + ScreenH
218b16d276SZihao Yu  val VTotal = VBackPorch + 23
22ec9268f7SZihao Yu}
238b16d276SZihao Yu
24ec9268f7SZihao Yutrait HasHDMIConst {
25ec9268f7SZihao Yu  val ScreenW = 800
26ec9268f7SZihao Yu  val ScreenH = 600
27ec9268f7SZihao Yu
28ec9268f7SZihao Yu  val HFrontPorch = 40
29ec9268f7SZihao Yu  val HActive = HFrontPorch + 128
30ec9268f7SZihao Yu  val HBackPorch = HActive + ScreenW
31ec9268f7SZihao Yu  val HTotal = HBackPorch + 88
32ec9268f7SZihao Yu  val VFrontPorch = 1
33ec9268f7SZihao Yu  val VActive = VFrontPorch + 4
34ec9268f7SZihao Yu  val VBackPorch = VActive + ScreenH
35ec9268f7SZihao Yu  val VTotal = VBackPorch + 23
36ec9268f7SZihao Yu}
37ec9268f7SZihao Yu
38ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst {
398b16d276SZihao Yu  val FBWidth = ScreenW / 2
408b16d276SZihao Yu  val FBHeight = ScreenH / 2
418b16d276SZihao Yu  val FBPixels = FBWidth * FBHeight
428b16d276SZihao Yu}
438b16d276SZihao Yu
448b16d276SZihao Yuclass VGABundle extends Bundle {
45ec9268f7SZihao Yu  val rgb = Output(UInt(24.W))
468b16d276SZihao Yu  val hsync = Output(Bool())
478b16d276SZihao Yu  val vsync = Output(Bool())
48ec9268f7SZihao Yu  val valid = Output(Bool())
498b16d276SZihao Yu}
508b16d276SZihao Yu
51096a786aSZihao Yuclass VGACtrlBundle extends Bundle {
52096a786aSZihao Yu  val sync = Output(Bool())
53096a786aSZihao Yu}
54096a786aSZihao Yu
55*226300c2Slinjiaweiclass VGACtrl
56*226300c2Slinjiawei(
57*226300c2Slinjiawei  address: AddressSet
58*226300c2Slinjiawei)(implicit p: Parameters)
59*226300c2Slinjiawei  extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter {
60*226300c2Slinjiawei  override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) {
61*226300c2Slinjiawei
628b16d276SZihao Yu    val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
638b16d276SZihao Yu    val sync = in.aw.fire()
64096a786aSZihao Yu
65096a786aSZihao Yu    val mapping = Map(
66096a786aSZihao Yu      RegMap(0x0, fbSizeReg, RegMap.Unwritable),
67096a786aSZihao Yu      RegMap(0x4, sync, RegMap.Unwritable)
68096a786aSZihao Yu    )
69096a786aSZihao Yu
70096a786aSZihao Yu    RegMap.generate(mapping, raddr(3, 0), in.r.bits.data,
71096a786aSZihao Yu      waddr(3, 0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb))
72096a786aSZihao Yu
73096a786aSZihao Yu    io.extra.get.sync := sync
748b16d276SZihao Yu  }
75*226300c2Slinjiawei}
768b16d276SZihao Yu
7743002b01SZihao Yuclass FBHelper extends BlackBox with HasBlackBoxInline {
7843002b01SZihao Yu  val io = IO(new Bundle {
7943002b01SZihao Yu    val clk = Input(Clock())
8043002b01SZihao Yu    val valid = Input(Bool())
8143002b01SZihao Yu    val pixel = Input(UInt(32.W))
8243002b01SZihao Yu    val sync = Input(Bool())
8343002b01SZihao Yu  })
8443002b01SZihao Yu
8543002b01SZihao Yu  setInline("FBHelper.v",
8643002b01SZihao Yu    s"""
8743002b01SZihao Yu       |import "DPI-C" function void put_pixel(input int pixel);
8843002b01SZihao Yu       |import "DPI-C" function void vmem_sync();
8943002b01SZihao Yu       |
9043002b01SZihao Yu       |module FBHelper (
9143002b01SZihao Yu       |  input clk,
9243002b01SZihao Yu       |  input valid,
9343002b01SZihao Yu       |  input [31:0] pixel,
9443002b01SZihao Yu       |  input sync
9543002b01SZihao Yu       |);
9643002b01SZihao Yu       |
9743002b01SZihao Yu       |  always@(posedge clk) begin
9843002b01SZihao Yu       |    if (valid) put_pixel(pixel);
9943002b01SZihao Yu       |    if (sync) vmem_sync();
10043002b01SZihao Yu       |  end
10143002b01SZihao Yu       |
10243002b01SZihao Yu       |endmodule
10343002b01SZihao Yu     """.stripMargin)
10443002b01SZihao Yu}
10543002b01SZihao Yu
106*226300c2Slinjiaweiclass AXI4VGA
107*226300c2Slinjiawei(
108*226300c2Slinjiawei  sim: Boolean = false,
109*226300c2Slinjiawei  fbAddress: AddressSet,
110*226300c2Slinjiawei  ctrlAddress: AddressSet
111*226300c2Slinjiawei)(implicit p: Parameters)
112*226300c2Slinjiawei  extends LazyModule with HasVGAParameter {
113*226300c2Slinjiawei
114*226300c2Slinjiawei
115*226300c2Slinjiawei  private val fb = LazyModule(new AXI4RAM(fbAddress, sim, false))
116*226300c2Slinjiawei  private val ctrl = LazyModule(new VGACtrl(ctrlAddress))
117*226300c2Slinjiawei
118*226300c2Slinjiawei  val node = AXI4IdentityNode()
119*226300c2Slinjiawei
120*226300c2Slinjiawei  fb.node := node
121*226300c2Slinjiawei  ctrl.node := node
122*226300c2Slinjiawei
123*226300c2Slinjiawei  lazy val module = new LazyModuleImp(this) {
124*226300c2Slinjiawei
125*226300c2Slinjiawei    val io = IO(new Bundle() {
1268b16d276SZihao Yu      val vga = new VGABundle
1278b16d276SZihao Yu    })
1288b16d276SZihao Yu
129*226300c2Slinjiawei    val out_fb = node.out.head._1
130*226300c2Slinjiawei    val out_ctrl = node.out.last._1
131*226300c2Slinjiawei    val in_fb = node.in.head._1
132*226300c2Slinjiawei    val in_ctrl = node.in.last._1
133*226300c2Slinjiawei
134*226300c2Slinjiawei    in_fb.ar.ready := true.B
135*226300c2Slinjiawei    in_fb.r.bits.data := 0.U
136*226300c2Slinjiawei    in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY
137*226300c2Slinjiawei    in_fb.r.valid := BoolStopWatch(in_fb.ar.fire(), in_fb.r.fire(), startHighPriority = true)
1388b16d276SZihao Yu
1398b16d276SZihao Yu    def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
1408b16d276SZihao Yu
1418b16d276SZihao Yu    val (hCounter, hFinish) = Counter(true.B, HTotal)
1428b16d276SZihao Yu    val (vCounter, vFinish) = Counter(hFinish, VTotal)
1438b16d276SZihao Yu    io.vga.hsync := hCounter >= HFrontPorch.U
1448b16d276SZihao Yu    io.vga.vsync := vCounter >= VFrontPorch.U
1458b16d276SZihao Yu
1468b16d276SZihao Yu    val hInRange = inRange(hCounter, HActive, HBackPorch)
1478b16d276SZihao Yu    val vInRange = inRange(vCounter, VActive, VBackPorch)
148ec9268f7SZihao Yu    io.vga.valid := hInRange && vInRange
1498b16d276SZihao Yu
1508b16d276SZihao Yu    val hCounterIsOdd = hCounter(0)
1519904078bSZihao Yu    val hCounterIs2 = hCounter(1, 0) === 2.U
1528b16d276SZihao Yu    val vCounterIsOdd = vCounter(0)
1539904078bSZihao Yu    // there is 2 cycle latency to read block memory,
1549904078bSZihao Yu    // so we should issue the read request 2 cycle eariler
1558b16d276SZihao Yu    val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
1568b16d276SZihao Yu    val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
1578b16d276SZihao Yu    val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1
1588b16d276SZihao Yu
1598b16d276SZihao Yu    //   each pixel is 4 bytes
160*226300c2Slinjiawei    out_fb.ar.bits.prot := 0.U
161*226300c2Slinjiawei    out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
162*226300c2Slinjiawei    out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2
1638b16d276SZihao Yu
164*226300c2Slinjiawei    out_fb.r.ready := true.B
165*226300c2Slinjiawei    val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire())
1669904078bSZihao Yu    val color = Mux(hCounter(1), data(63, 32), data(31, 0))
167ec9268f7SZihao Yu    io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
16843002b01SZihao Yu
16943002b01SZihao Yu    if (sim) {
17043002b01SZihao Yu      val fbHelper = Module(new FBHelper)
17143002b01SZihao Yu      fbHelper.io.clk := clock
172ec9268f7SZihao Yu      fbHelper.io.valid := io.vga.valid
17343002b01SZihao Yu      fbHelper.io.pixel := color
174*226300c2Slinjiawei      fbHelper.io.sync := ctrl.module.io.extra.get.sync
17543002b01SZihao Yu    }
176*226300c2Slinjiawei
177*226300c2Slinjiawei  }
178*226300c2Slinjiawei
179*226300c2Slinjiawei  //  val AXIidBits = 2
180*226300c2Slinjiawei  //  val io = IO(new Bundle {
181*226300c2Slinjiawei  //    val in = new Bundle {
182*226300c2Slinjiawei  //      val fb = Flipped(new AXI4Lite)
183*226300c2Slinjiawei  //      val ctrl = Flipped(new AXI4Lite)
184*226300c2Slinjiawei  //    }
185*226300c2Slinjiawei  //    val vga = new VGABundle
186*226300c2Slinjiawei  //  })
187*226300c2Slinjiawei  //
188*226300c2Slinjiawei  //  val ctrl = Module(new VGACtrl)
189*226300c2Slinjiawei  //  io.in.ctrl <> ctrl.io.in
190*226300c2Slinjiawei  //  val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4))
191*226300c2Slinjiawei  //  // writable by axi4lite
192*226300c2Slinjiawei  //  // but it only readable by the internel controller
193*226300c2Slinjiawei  //  fb.io.in.aw <> io.in.fb.aw
194*226300c2Slinjiawei  //  fb.io.in.w <> io.in.fb.w
195*226300c2Slinjiawei  //  io.in.fb.b <> fb.io.in.b
196*226300c2Slinjiawei  //  io.in.fb.ar.ready := true.B
197*226300c2Slinjiawei  //  io.in.fb.r.bits.data := 0.U
198*226300c2Slinjiawei  //  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
199*226300c2Slinjiawei  //  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true)
200*226300c2Slinjiawei  //
201*226300c2Slinjiawei  //  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
202*226300c2Slinjiawei  //
203*226300c2Slinjiawei  //  val (hCounter, hFinish) = Counter(true.B, HTotal)
204*226300c2Slinjiawei  //  val (vCounter, vFinish) = Counter(hFinish, VTotal)
205*226300c2Slinjiawei  //
206*226300c2Slinjiawei  //  io.vga.hsync := hCounter >= HFrontPorch.U
207*226300c2Slinjiawei  //  io.vga.vsync := vCounter >= VFrontPorch.U
208*226300c2Slinjiawei  //
209*226300c2Slinjiawei  //  val hInRange = inRange(hCounter, HActive, HBackPorch)
210*226300c2Slinjiawei  //  val vInRange = inRange(vCounter, VActive, VBackPorch)
211*226300c2Slinjiawei  //  io.vga.valid := hInRange && vInRange
212*226300c2Slinjiawei  //
213*226300c2Slinjiawei  //  val hCounterIsOdd = hCounter(0)
214*226300c2Slinjiawei  //  val hCounterIs2 = hCounter(1,0) === 2.U
215*226300c2Slinjiawei  //  val vCounterIsOdd = vCounter(0)
216*226300c2Slinjiawei  //  // there is 2 cycle latency to read block memory,
217*226300c2Slinjiawei  //  // so we should issue the read request 2 cycle eariler
218*226300c2Slinjiawei  //  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
219*226300c2Slinjiawei  //  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
220*226300c2Slinjiawei  //  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
221*226300c2Slinjiawei  //
222*226300c2Slinjiawei  //  // each pixel is 4 bytes
223*226300c2Slinjiawei  //  fb.io.in.ar.bits.prot := 0.U
224*226300c2Slinjiawei  //  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
225*226300c2Slinjiawei  //  fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2
226*226300c2Slinjiawei  //
227*226300c2Slinjiawei  //  fb.io.in.r.ready := true.B
228*226300c2Slinjiawei  //  val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire())
229*226300c2Slinjiawei  //  val color = Mux(hCounter(1), data(63, 32), data(31, 0))
230*226300c2Slinjiawei  //  io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
231*226300c2Slinjiawei  //
232*226300c2Slinjiawei  //  if (sim) {
233*226300c2Slinjiawei  //    val fbHelper = Module(new FBHelper)
234*226300c2Slinjiawei  //    fbHelper.io.clk := clock
235*226300c2Slinjiawei  //    fbHelper.io.valid := io.vga.valid
236*226300c2Slinjiawei  //    fbHelper.io.pixel := color
237*226300c2Slinjiawei  //    fbHelper.io.sync := ctrl.io.extra.get.sync
238*226300c2Slinjiawei  //  }
2398b16d276SZihao Yu}
240