xref: /XiangShan/src/main/scala/device/AXI4VGA.scala (revision 4b3d9f67355a9945cd5eca46929b89c130c43c26)
1package device
2
3import chisel3._
4import chisel3.util._
5import chipsalliance.rocketchip.config.Parameters
6import freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar}
7import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType}
8import utils._
9
10trait HasVGAConst {
11  val ScreenW = 800
12  val ScreenH = 600
13
14  val HFrontPorch = 56
15  val HActive = HFrontPorch + 120
16  val HBackPorch = HActive + ScreenW
17  val HTotal = HBackPorch + 64
18  val VFrontPorch = 37
19  val VActive = VFrontPorch + 6
20  val VBackPorch = VActive + ScreenH
21  val VTotal = VBackPorch + 23
22}
23
24trait HasHDMIConst {
25  val ScreenW = 800
26  val ScreenH = 600
27
28  val HFrontPorch = 40
29  val HActive = HFrontPorch + 128
30  val HBackPorch = HActive + ScreenW
31  val HTotal = HBackPorch + 88
32  val VFrontPorch = 1
33  val VActive = VFrontPorch + 4
34  val VBackPorch = VActive + ScreenH
35  val VTotal = VBackPorch + 23
36}
37
38trait HasVGAParameter extends HasHDMIConst {
39  val FBWidth = ScreenW / 2
40  val FBHeight = ScreenH / 2
41  val FBPixels = FBWidth * FBHeight
42}
43
44class VGABundle extends Bundle {
45  val rgb = Output(UInt(24.W))
46  val hsync = Output(Bool())
47  val vsync = Output(Bool())
48  val valid = Output(Bool())
49}
50
51class VGACtrlBundle extends Bundle {
52  val sync = Output(Bool())
53}
54
55class VGACtrl
56(
57  address: Seq[AddressSet]
58)(implicit p: Parameters)
59  extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter {
60  override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) {
61
62    val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W))
63    val sync = in.aw.fire()
64
65    val mapping = Map(
66      RegMap(0x0, fbSizeReg, RegMap.Unwritable),
67      RegMap(0x4, sync, RegMap.Unwritable)
68    )
69
70    RegMap.generate(mapping, raddr(3, 0), in.r.bits.data,
71      waddr(3, 0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb))
72
73    io.extra.get.sync := sync
74  }
75}
76
77class FBHelper extends BlackBox with HasBlackBoxInline {
78  val io = IO(new Bundle {
79    val clk = Input(Clock())
80    val valid = Input(Bool())
81    val pixel = Input(UInt(32.W))
82    val sync = Input(Bool())
83  })
84
85  setInline("FBHelper.v",
86    s"""
87       |import "DPI-C" function void put_pixel(input int pixel);
88       |import "DPI-C" function void vmem_sync();
89       |
90       |module FBHelper (
91       |  input clk,
92       |  input valid,
93       |  input [31:0] pixel,
94       |  input sync
95       |);
96       |
97       |  always@(posedge clk) begin
98       |    if (valid) put_pixel(pixel);
99       |    if (sync) vmem_sync();
100       |  end
101       |
102       |endmodule
103     """.stripMargin)
104}
105
106class AXI4VGA
107(
108  sim: Boolean = false,
109  fbAddress: Seq[AddressSet],
110  ctrlAddress: Seq[AddressSet]
111)(implicit p: Parameters)
112  extends LazyModule with HasVGAParameter {
113
114
115  private val fb = LazyModule(new AXI4RAM(
116    fbAddress,
117    memByte= FBPixels * 4,
118    sim,
119    executable = false
120  ))
121  private val ctrl = LazyModule(new VGACtrl(ctrlAddress))
122
123  val node = AXI4IdentityNode()
124
125  fb.node := node
126  ctrl.node := node
127
128  lazy val module = new LazyModuleImp(this) {
129
130    val io = IO(new Bundle() {
131      val vga = new VGABundle
132    })
133
134    val out_fb = node.out.head._1
135    val out_ctrl = node.out.last._1
136    val in_fb = node.in.head._1
137    val in_ctrl = node.in.last._1
138
139    in_fb.ar.ready := true.B
140    in_fb.r.bits.data := 0.U
141    in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY
142    in_fb.r.valid := BoolStopWatch(in_fb.ar.fire(), in_fb.r.fire(), startHighPriority = true)
143
144    def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
145
146    val (hCounter, hFinish) = Counter(true.B, HTotal)
147    val (vCounter, vFinish) = Counter(hFinish, VTotal)
148    io.vga.hsync := hCounter >= HFrontPorch.U
149    io.vga.vsync := vCounter >= VFrontPorch.U
150
151    val hInRange = inRange(hCounter, HActive, HBackPorch)
152    val vInRange = inRange(vCounter, VActive, VBackPorch)
153    io.vga.valid := hInRange && vInRange
154
155    val hCounterIsOdd = hCounter(0)
156    val hCounterIs2 = hCounter(1, 0) === 2.U
157    val vCounterIsOdd = vCounter(0)
158    // there is 2 cycle latency to read block memory,
159    // so we should issue the read request 2 cycle eariler
160    val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
161    val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
162    val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1
163
164    //   each pixel is 4 bytes
165    out_fb.ar.bits.prot := 0.U
166    out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
167    out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2
168
169    out_fb.r.ready := true.B
170    val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire())
171    val color = Mux(hCounter(1), data(63, 32), data(31, 0))
172    io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
173
174    if (sim) {
175      val fbHelper = Module(new FBHelper)
176      fbHelper.io.clk := clock
177      fbHelper.io.valid := io.vga.valid
178      fbHelper.io.pixel := color
179      fbHelper.io.sync := ctrl.module.io.extra.get.sync
180    }
181
182  }
183
184  //  val AXIidBits = 2
185  //  val io = IO(new Bundle {
186  //    val in = new Bundle {
187  //      val fb = Flipped(new AXI4Lite)
188  //      val ctrl = Flipped(new AXI4Lite)
189  //    }
190  //    val vga = new VGABundle
191  //  })
192  //
193  //  val ctrl = Module(new VGACtrl)
194  //  io.in.ctrl <> ctrl.io.in
195  //  val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4))
196  //  // writable by axi4lite
197  //  // but it only readable by the internel controller
198  //  fb.io.in.aw <> io.in.fb.aw
199  //  fb.io.in.w <> io.in.fb.w
200  //  io.in.fb.b <> fb.io.in.b
201  //  io.in.fb.ar.ready := true.B
202  //  io.in.fb.r.bits.data := 0.U
203  //  io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY
204  //  io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true)
205  //
206  //  def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U)
207  //
208  //  val (hCounter, hFinish) = Counter(true.B, HTotal)
209  //  val (vCounter, vFinish) = Counter(hFinish, VTotal)
210  //
211  //  io.vga.hsync := hCounter >= HFrontPorch.U
212  //  io.vga.vsync := vCounter >= VFrontPorch.U
213  //
214  //  val hInRange = inRange(hCounter, HActive, HBackPorch)
215  //  val vInRange = inRange(vCounter, VActive, VBackPorch)
216  //  io.vga.valid := hInRange && vInRange
217  //
218  //  val hCounterIsOdd = hCounter(0)
219  //  val hCounterIs2 = hCounter(1,0) === 2.U
220  //  val vCounterIsOdd = vCounter(0)
221  //  // there is 2 cycle latency to read block memory,
222  //  // so we should issue the read request 2 cycle eariler
223  //  val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd
224  //  val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1
225  //  val fbPixelAddrV1 = Counter(nextPixel &&  vCounterIsOdd, FBPixels)._1
226  //
227  //  // each pixel is 4 bytes
228  //  fb.io.in.ar.bits.prot := 0.U
229  //  fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W))
230  //  fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2
231  //
232  //  fb.io.in.r.ready := true.B
233  //  val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire())
234  //  val color = Mux(hCounter(1), data(63, 32), data(31, 0))
235  //  io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U)
236  //
237  //  if (sim) {
238  //    val fbHelper = Module(new FBHelper)
239  //    fbHelper.io.clk := clock
240  //    fbHelper.io.valid := io.vga.valid
241  //    fbHelper.io.pixel := color
242  //    fbHelper.io.sync := ctrl.io.extra.get.sync
243  //  }
244}
245