xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision ec9268f762f3fd22ec8e384a864c07b3023b87fc)
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  val ScreenW = 800
118b16d276SZihao Yu  val ScreenH = 600
128b16d276SZihao Yu
138b16d276SZihao Yu  val HFrontPorch = 56
148b16d276SZihao Yu  val HActive = HFrontPorch + 120
158b16d276SZihao Yu  val HBackPorch = HActive + ScreenW
168b16d276SZihao Yu  val HTotal = HBackPorch + 64
178b16d276SZihao Yu  val VFrontPorch = 37
188b16d276SZihao Yu  val VActive = VFrontPorch + 6
198b16d276SZihao Yu  val VBackPorch = VActive + ScreenH
208b16d276SZihao Yu  val VTotal = VBackPorch + 23
21*ec9268f7SZihao Yu}
228b16d276SZihao Yu
23*ec9268f7SZihao Yutrait HasHDMIConst {
24*ec9268f7SZihao Yu  val ScreenW = 800
25*ec9268f7SZihao Yu  val ScreenH = 600
26*ec9268f7SZihao Yu
27*ec9268f7SZihao Yu  val HFrontPorch = 40
28*ec9268f7SZihao Yu  val HActive = HFrontPorch + 128
29*ec9268f7SZihao Yu  val HBackPorch = HActive + ScreenW
30*ec9268f7SZihao Yu  val HTotal = HBackPorch + 88
31*ec9268f7SZihao Yu  val VFrontPorch = 1
32*ec9268f7SZihao Yu  val VActive = VFrontPorch + 4
33*ec9268f7SZihao Yu  val VBackPorch = VActive + ScreenH
34*ec9268f7SZihao Yu  val VTotal = VBackPorch + 23
35*ec9268f7SZihao Yu}
36*ec9268f7SZihao Yu
37*ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst {
388b16d276SZihao Yu  val FBWidth = ScreenW / 2
398b16d276SZihao Yu  val FBHeight = ScreenH / 2
408b16d276SZihao Yu  val FBPixels = FBWidth * FBHeight
418b16d276SZihao Yu}
428b16d276SZihao Yu
438b16d276SZihao Yuclass VGABundle extends Bundle {
44*ec9268f7SZihao Yu  val rgb = Output(UInt(24.W))
458b16d276SZihao Yu  val hsync = Output(Bool())
468b16d276SZihao Yu  val vsync = Output(Bool())
47*ec9268f7SZihao Yu  val valid = Output(Bool())
488b16d276SZihao Yu}
498b16d276SZihao Yu
50096a786aSZihao Yuclass VGACtrlBundle extends Bundle {
51096a786aSZihao Yu  val sync = Output(Bool())
52096a786aSZihao Yu}
53096a786aSZihao Yu
54*ec9268f7SZihao Yuclass VGACtrl extends AXI4SlaveModule(new AXI4Lite, new VGACtrlBundle) with HasVGAParameter {
558b16d276SZihao Yu  val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
568b16d276SZihao Yu  val sync = in.aw.fire()
57096a786aSZihao Yu
58096a786aSZihao Yu  val mapping = Map(
59096a786aSZihao Yu    RegMap(0x0, fbSizeReg, RegMap.Unwritable),
60096a786aSZihao Yu    RegMap(0x4, sync, RegMap.Unwritable)
61096a786aSZihao Yu  )
62096a786aSZihao Yu
63096a786aSZihao Yu  RegMap.generate(mapping, raddr(3,0), in.r.bits.data,
64096a786aSZihao Yu    waddr(3,0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb))
65096a786aSZihao Yu
66096a786aSZihao Yu  io.extra.get.sync := sync
678b16d276SZihao Yu}
688b16d276SZihao Yu
6943002b01SZihao Yuclass FBHelper extends BlackBox with HasBlackBoxInline {
7043002b01SZihao Yu  val io = IO(new Bundle {
7143002b01SZihao Yu    val clk = Input(Clock())
7243002b01SZihao Yu    val valid = Input(Bool())
7343002b01SZihao Yu    val pixel = Input(UInt(32.W))
7443002b01SZihao Yu    val sync = Input(Bool())
7543002b01SZihao Yu  })
7643002b01SZihao Yu
7743002b01SZihao Yu  setInline("FBHelper.v",
7843002b01SZihao Yu    s"""
7943002b01SZihao Yu      |import "DPI-C" function void put_pixel(input int pixel);
8043002b01SZihao Yu      |import "DPI-C" function void vmem_sync();
8143002b01SZihao Yu      |
8243002b01SZihao Yu      |module FBHelper (
8343002b01SZihao Yu      |  input clk,
8443002b01SZihao Yu      |  input valid,
8543002b01SZihao Yu      |  input [31:0] pixel,
8643002b01SZihao Yu      |  input sync
8743002b01SZihao Yu      |);
8843002b01SZihao Yu      |
8943002b01SZihao Yu      |  always@(posedge clk) begin
9043002b01SZihao Yu      |    if (valid) put_pixel(pixel);
9143002b01SZihao Yu      |    if (sync) vmem_sync();
9243002b01SZihao Yu      |  end
9343002b01SZihao Yu      |
9443002b01SZihao Yu      |endmodule
9543002b01SZihao Yu     """.stripMargin)
9643002b01SZihao Yu}
9743002b01SZihao Yu
98*ec9268f7SZihao Yuclass AXI4VGA(sim: Boolean = false) extends Module with HasVGAParameter {
99466a6a49SZihao Yu  val AXIidBits = 2
1008b16d276SZihao Yu  val io = IO(new Bundle {
1018b16d276SZihao Yu    val in = new Bundle {
10211348640SZihao Yu      val fb = Flipped(new AXI4Lite)
1038b16d276SZihao Yu      val ctrl = Flipped(new AXI4Lite)
1048b16d276SZihao Yu    }
1058b16d276SZihao Yu    val vga = new VGABundle
1068b16d276SZihao Yu  })
1078b16d276SZihao Yu
1088b16d276SZihao Yu  val ctrl = Module(new VGACtrl)
1098b16d276SZihao Yu  io.in.ctrl <> ctrl.io.in
11011348640SZihao Yu  val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4))
1118b16d276SZihao Yu  // writable by axi4lite
1128b16d276SZihao Yu  // but it only readable by the internel controller
1138b16d276SZihao Yu  fb.io.in.aw <> io.in.fb.aw
1148b16d276SZihao Yu  fb.io.in.w <> io.in.fb.w
1158b16d276SZihao Yu  io.in.fb.b <> fb.io.in.b
1168b16d276SZihao Yu  io.in.fb.ar.ready := true.B
1178b16d276SZihao Yu  io.in.fb.r.bits.data := 0.U
1188b16d276SZihao Yu  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
1198b16d276SZihao Yu  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true)
1208b16d276SZihao Yu
1218b16d276SZihao Yu  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
1228b16d276SZihao Yu
1238b16d276SZihao Yu  val (hCounter, hFinish) = Counter(true.B, HTotal)
1248b16d276SZihao Yu  val (vCounter, vFinish) = Counter(hFinish, VTotal)
1258b16d276SZihao Yu
1268b16d276SZihao Yu  io.vga.hsync := hCounter >= HFrontPorch.U
1278b16d276SZihao Yu  io.vga.vsync := vCounter >= VFrontPorch.U
1288b16d276SZihao Yu
1298b16d276SZihao Yu  val hInRange = inRange(hCounter, HActive, HBackPorch)
1308b16d276SZihao Yu  val vInRange = inRange(vCounter, VActive, VBackPorch)
131*ec9268f7SZihao Yu  io.vga.valid := hInRange && vInRange
1328b16d276SZihao Yu
1338b16d276SZihao Yu  val hCounterIsOdd = hCounter(0)
1349904078bSZihao Yu  val hCounterIs2 = hCounter(1,0) === 2.U
1358b16d276SZihao Yu  val vCounterIsOdd = vCounter(0)
1369904078bSZihao Yu  // there is 2 cycle latency to read block memory,
1379904078bSZihao Yu  // so we should issue the read request 2 cycle eariler
1388b16d276SZihao Yu  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
1398b16d276SZihao Yu  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
1408b16d276SZihao Yu  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
1418b16d276SZihao Yu
1428b16d276SZihao Yu  // each pixel is 4 bytes
14311348640SZihao Yu  fb.io.in.ar.bits.prot := 0.U
1448b16d276SZihao Yu  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
1459904078bSZihao Yu  fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2
1468b16d276SZihao Yu
1478b16d276SZihao Yu  fb.io.in.r.ready := true.B
1489904078bSZihao Yu  val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire())
1499904078bSZihao Yu  val color = Mux(hCounter(1), data(63, 32), data(31, 0))
150*ec9268f7SZihao Yu  io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
15143002b01SZihao Yu
15243002b01SZihao Yu  if (sim) {
15343002b01SZihao Yu    val fbHelper = Module(new FBHelper)
15443002b01SZihao Yu    fbHelper.io.clk := clock
155*ec9268f7SZihao Yu    fbHelper.io.valid := io.vga.valid
15643002b01SZihao Yu    fbHelper.io.pixel := color
15743002b01SZihao Yu    fbHelper.io.sync := ctrl.io.extra.get.sync
15843002b01SZihao Yu  }
1598b16d276SZihao Yu}
160