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