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