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