xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision 096a786a1d58777db9573ebff6507b6c76069614)
18b16d276SZihao Yupackage device
28b16d276SZihao Yu
38b16d276SZihao Yuimport chisel3._
48b16d276SZihao Yuimport chisel3.util._
58b16d276SZihao Yu
68b16d276SZihao Yuimport bus.axi4._
78b16d276SZihao Yuimport utils._
88b16d276SZihao Yu
98b16d276SZihao Yutrait HasVGAConst {
108b16d276SZihao Yu  // these are only fit for 800x600
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
228b16d276SZihao Yu
238b16d276SZihao Yu  val FBWidth = ScreenW / 2
248b16d276SZihao Yu  val FBHeight = ScreenH / 2
258b16d276SZihao Yu  val FBPixels = FBWidth * FBHeight
268b16d276SZihao Yu}
278b16d276SZihao Yu
288b16d276SZihao Yuclass VGABundle extends Bundle {
298b16d276SZihao Yu  val r = Output(UInt(4.W))
308b16d276SZihao Yu  val g = Output(UInt(4.W))
318b16d276SZihao Yu  val b = Output(UInt(4.W))
328b16d276SZihao Yu  val hsync = Output(Bool())
338b16d276SZihao Yu  val vsync = Output(Bool())
348b16d276SZihao Yu}
358b16d276SZihao Yu
36*096a786aSZihao Yuclass VGACtrlBundle extends Bundle {
37*096a786aSZihao Yu  val sync = Output(Bool())
38*096a786aSZihao Yu}
39*096a786aSZihao Yu
40*096a786aSZihao Yuclass VGACtrl extends AXI4SlaveModule(new AXI4Lite, new VGACtrlBundle) with HasVGAConst {
418b16d276SZihao Yu  val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
428b16d276SZihao Yu  val sync = in.aw.fire()
43*096a786aSZihao Yu
44*096a786aSZihao Yu  val mapping = Map(
45*096a786aSZihao Yu    RegMap(0x0, fbSizeReg, RegMap.Unwritable),
46*096a786aSZihao Yu    RegMap(0x4, sync, RegMap.Unwritable)
47*096a786aSZihao Yu  )
48*096a786aSZihao Yu
49*096a786aSZihao Yu  RegMap.generate(mapping, raddr(3,0), in.r.bits.data,
50*096a786aSZihao Yu    waddr(3,0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb))
51*096a786aSZihao Yu
52*096a786aSZihao Yu  io.extra.get.sync := sync
538b16d276SZihao Yu}
548b16d276SZihao Yu
558b16d276SZihao Yuclass AXI4VGA extends Module with HasVGAConst {
56466a6a49SZihao Yu  val AXIidBits = 2
578b16d276SZihao Yu  // need a 50MHz clock
588b16d276SZihao Yu  val io = IO(new Bundle {
598b16d276SZihao Yu    val in = new Bundle {
6011348640SZihao Yu      val fb = Flipped(new AXI4Lite)
618b16d276SZihao Yu      val ctrl = Flipped(new AXI4Lite)
628b16d276SZihao Yu    }
638b16d276SZihao Yu    val vga = new VGABundle
648b16d276SZihao Yu  })
658b16d276SZihao Yu
668b16d276SZihao Yu  val ctrl = Module(new VGACtrl)
678b16d276SZihao Yu  io.in.ctrl <> ctrl.io.in
6811348640SZihao Yu  val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4))
698b16d276SZihao Yu  // writable by axi4lite
708b16d276SZihao Yu  // but it only readable by the internel controller
718b16d276SZihao Yu  fb.io.in.aw <> io.in.fb.aw
728b16d276SZihao Yu  fb.io.in.w <> io.in.fb.w
738b16d276SZihao Yu  io.in.fb.b <> fb.io.in.b
748b16d276SZihao Yu  io.in.fb.ar.ready := true.B
758b16d276SZihao Yu  io.in.fb.r.bits.data := 0.U
768b16d276SZihao Yu  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
778b16d276SZihao Yu  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true)
788b16d276SZihao Yu
798b16d276SZihao Yu  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
808b16d276SZihao Yu
818b16d276SZihao Yu  val (hCounter, hFinish) = Counter(true.B, HTotal)
828b16d276SZihao Yu  val (vCounter, vFinish) = Counter(hFinish, VTotal)
838b16d276SZihao Yu
848b16d276SZihao Yu  io.vga.hsync := hCounter >= HFrontPorch.U
858b16d276SZihao Yu  io.vga.vsync := vCounter >= VFrontPorch.U
868b16d276SZihao Yu
878b16d276SZihao Yu  val hInRange = inRange(hCounter, HActive, HBackPorch)
888b16d276SZihao Yu  val vInRange = inRange(vCounter, VActive, VBackPorch)
898b16d276SZihao Yu  val videoValid = hInRange && vInRange
908b16d276SZihao Yu
918b16d276SZihao Yu  val hCounterIsOdd = hCounter(0)
929904078bSZihao Yu  val hCounterIs2 = hCounter(1,0) === 2.U
938b16d276SZihao Yu  val vCounterIsOdd = vCounter(0)
949904078bSZihao Yu  // there is 2 cycle latency to read block memory,
959904078bSZihao Yu  // so we should issue the read request 2 cycle eariler
968b16d276SZihao Yu  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
978b16d276SZihao Yu  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
988b16d276SZihao Yu  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
998b16d276SZihao Yu
1008b16d276SZihao Yu  // each pixel is 4 bytes
10111348640SZihao Yu  fb.io.in.ar.bits.prot := 0.U
1028b16d276SZihao Yu  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
1039904078bSZihao Yu  fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2
1048b16d276SZihao Yu
1058b16d276SZihao Yu  fb.io.in.r.ready := true.B
1069904078bSZihao Yu  val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire())
1079904078bSZihao Yu  val color = Mux(hCounter(1), data(63, 32), data(31, 0))
1088b16d276SZihao Yu  io.vga.r := Mux(videoValid, color(23, 20), 0.U)
1098b16d276SZihao Yu  io.vga.g := Mux(videoValid, color(15, 12), 0.U)
1108b16d276SZihao Yu  io.vga.b := Mux(videoValid, color(7, 4), 0.U)
1118b16d276SZihao Yu}
112