xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision 8b16d276549bcdf1918d0a95a4dd1df9ba9aeed5)
1*8b16d276SZihao Yupackage device
2*8b16d276SZihao Yu
3*8b16d276SZihao Yuimport chisel3._
4*8b16d276SZihao Yuimport chisel3.util._
5*8b16d276SZihao Yu
6*8b16d276SZihao Yuimport bus.axi4._
7*8b16d276SZihao Yuimport utils._
8*8b16d276SZihao Yu
9*8b16d276SZihao Yutrait HasVGAConst {
10*8b16d276SZihao Yu  // these are only fit for 800x600
11*8b16d276SZihao Yu  val ScreenW = 800
12*8b16d276SZihao Yu  val ScreenH = 600
13*8b16d276SZihao Yu
14*8b16d276SZihao Yu  val HFrontPorch = 56
15*8b16d276SZihao Yu  val HActive = HFrontPorch + 120
16*8b16d276SZihao Yu  val HBackPorch = HActive + ScreenW
17*8b16d276SZihao Yu  val HTotal = HBackPorch + 64
18*8b16d276SZihao Yu  val VFrontPorch = 37
19*8b16d276SZihao Yu  val VActive = VFrontPorch + 6
20*8b16d276SZihao Yu  val VBackPorch = VActive + ScreenH
21*8b16d276SZihao Yu  val VTotal = VBackPorch + 23
22*8b16d276SZihao Yu
23*8b16d276SZihao Yu  val FBWidth = ScreenW / 2
24*8b16d276SZihao Yu  val FBHeight = ScreenH / 2
25*8b16d276SZihao Yu  val FBPixels = FBWidth * FBHeight
26*8b16d276SZihao Yu}
27*8b16d276SZihao Yu
28*8b16d276SZihao Yuclass VGABundle extends Bundle {
29*8b16d276SZihao Yu  val r = Output(UInt(4.W))
30*8b16d276SZihao Yu  val g = Output(UInt(4.W))
31*8b16d276SZihao Yu  val b = Output(UInt(4.W))
32*8b16d276SZihao Yu  val hsync = Output(Bool())
33*8b16d276SZihao Yu  val vsync = Output(Bool())
34*8b16d276SZihao Yu}
35*8b16d276SZihao Yu
36*8b16d276SZihao Yuclass VGACtrl extends AXI4SlaveModule(new AXI4Lite) with HasVGAConst {
37*8b16d276SZihao Yu  // actually this is a constant
38*8b16d276SZihao Yu  val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
39*8b16d276SZihao Yu  // we always return fbSizeReg to axi4lite
40*8b16d276SZihao Yu  in.r.bits.data := fbSizeReg
41*8b16d276SZihao Yu  val sync = in.aw.fire()
42*8b16d276SZihao Yu}
43*8b16d276SZihao Yu
44*8b16d276SZihao Yuclass AXI4VGA extends Module with HasVGAConst {
45*8b16d276SZihao Yu  // need a 50MHz clock
46*8b16d276SZihao Yu  val io = IO(new Bundle {
47*8b16d276SZihao Yu    val in = new Bundle {
48*8b16d276SZihao Yu      val fb = Flipped(new AXI4Lite)
49*8b16d276SZihao Yu      val ctrl = Flipped(new AXI4Lite)
50*8b16d276SZihao Yu    }
51*8b16d276SZihao Yu    val vga = new VGABundle
52*8b16d276SZihao Yu  })
53*8b16d276SZihao Yu
54*8b16d276SZihao Yu  val ctrl = Module(new VGACtrl)
55*8b16d276SZihao Yu  io.in.ctrl <> ctrl.io.in
56*8b16d276SZihao Yu  val fb = Module(new AXI4RAM(_type = new AXI4Lite, FBPixels * 4))
57*8b16d276SZihao Yu  // writable by axi4lite
58*8b16d276SZihao Yu  // but it only readable by the internel controller
59*8b16d276SZihao Yu  fb.io.in.aw <> io.in.fb.aw
60*8b16d276SZihao Yu  fb.io.in.w <> io.in.fb.w
61*8b16d276SZihao Yu  io.in.fb.b <> fb.io.in.b
62*8b16d276SZihao Yu  io.in.fb.ar.ready := true.B
63*8b16d276SZihao Yu  io.in.fb.r.bits.data := 0.U
64*8b16d276SZihao Yu  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
65*8b16d276SZihao Yu  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true)
66*8b16d276SZihao Yu
67*8b16d276SZihao Yu  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
68*8b16d276SZihao Yu
69*8b16d276SZihao Yu  val (hCounter, hFinish) = Counter(true.B, HTotal)
70*8b16d276SZihao Yu  val (vCounter, vFinish) = Counter(hFinish, VTotal)
71*8b16d276SZihao Yu
72*8b16d276SZihao Yu  io.vga.hsync := hCounter >= HFrontPorch.U
73*8b16d276SZihao Yu  io.vga.vsync := vCounter >= VFrontPorch.U
74*8b16d276SZihao Yu
75*8b16d276SZihao Yu  val hInRange = inRange(hCounter, HActive, HBackPorch)
76*8b16d276SZihao Yu  val vInRange = inRange(vCounter, VActive, VBackPorch)
77*8b16d276SZihao Yu  val videoValid = hInRange && vInRange
78*8b16d276SZihao Yu
79*8b16d276SZihao Yu  val hCounterIsOdd = hCounter(0)
80*8b16d276SZihao Yu  val vCounterIsOdd = vCounter(0)
81*8b16d276SZihao Yu  // there is 1 cycle latency to read block memory,
82*8b16d276SZihao Yu  // so we should issue the read request 1 cycle eariler
83*8b16d276SZihao Yu  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
84*8b16d276SZihao Yu  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
85*8b16d276SZihao Yu  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
86*8b16d276SZihao Yu
87*8b16d276SZihao Yu  // each pixel is 4 bytes
88*8b16d276SZihao Yu  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
89*8b16d276SZihao Yu  fb.io.in.ar.bits.prot := DontCare
90*8b16d276SZihao Yu  fb.io.in.ar.valid := nextPixel
91*8b16d276SZihao Yu
92*8b16d276SZihao Yu  fb.io.in.r.ready := true.B
93*8b16d276SZihao Yu  val color = fb.io.in.r.bits.data
94*8b16d276SZihao Yu  io.vga.r := Mux(videoValid, color(23, 20), 0.U)
95*8b16d276SZihao Yu  io.vga.g := Mux(videoValid, color(15, 12), 0.U)
96*8b16d276SZihao Yu  io.vga.b := Mux(videoValid, color(7, 4), 0.U)
97*8b16d276SZihao Yu}
98