18b16d276SZihao Yupackage device 28b16d276SZihao Yu 38b16d276SZihao Yuimport chisel3._ 48b16d276SZihao Yuimport chisel3.util._ 5*226300c2Slinjiaweiimport chipsalliance.rocketchip.config.Parameters 6*226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar} 7*226300c2Slinjiaweiimport freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType} 88b16d276SZihao Yuimport utils._ 98b16d276SZihao Yu 108b16d276SZihao Yutrait HasVGAConst { 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 22ec9268f7SZihao Yu} 238b16d276SZihao Yu 24ec9268f7SZihao Yutrait HasHDMIConst { 25ec9268f7SZihao Yu val ScreenW = 800 26ec9268f7SZihao Yu val ScreenH = 600 27ec9268f7SZihao Yu 28ec9268f7SZihao Yu val HFrontPorch = 40 29ec9268f7SZihao Yu val HActive = HFrontPorch + 128 30ec9268f7SZihao Yu val HBackPorch = HActive + ScreenW 31ec9268f7SZihao Yu val HTotal = HBackPorch + 88 32ec9268f7SZihao Yu val VFrontPorch = 1 33ec9268f7SZihao Yu val VActive = VFrontPorch + 4 34ec9268f7SZihao Yu val VBackPorch = VActive + ScreenH 35ec9268f7SZihao Yu val VTotal = VBackPorch + 23 36ec9268f7SZihao Yu} 37ec9268f7SZihao Yu 38ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst { 398b16d276SZihao Yu val FBWidth = ScreenW / 2 408b16d276SZihao Yu val FBHeight = ScreenH / 2 418b16d276SZihao Yu val FBPixels = FBWidth * FBHeight 428b16d276SZihao Yu} 438b16d276SZihao Yu 448b16d276SZihao Yuclass VGABundle extends Bundle { 45ec9268f7SZihao Yu val rgb = Output(UInt(24.W)) 468b16d276SZihao Yu val hsync = Output(Bool()) 478b16d276SZihao Yu val vsync = Output(Bool()) 48ec9268f7SZihao Yu val valid = Output(Bool()) 498b16d276SZihao Yu} 508b16d276SZihao Yu 51096a786aSZihao Yuclass VGACtrlBundle extends Bundle { 52096a786aSZihao Yu val sync = Output(Bool()) 53096a786aSZihao Yu} 54096a786aSZihao Yu 55*226300c2Slinjiaweiclass VGACtrl 56*226300c2Slinjiawei( 57*226300c2Slinjiawei address: AddressSet 58*226300c2Slinjiawei)(implicit p: Parameters) 59*226300c2Slinjiawei extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter { 60*226300c2Slinjiawei override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) { 61*226300c2Slinjiawei 628b16d276SZihao Yu val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W)) 638b16d276SZihao Yu val sync = in.aw.fire() 64096a786aSZihao Yu 65096a786aSZihao Yu val mapping = Map( 66096a786aSZihao Yu RegMap(0x0, fbSizeReg, RegMap.Unwritable), 67096a786aSZihao Yu RegMap(0x4, sync, RegMap.Unwritable) 68096a786aSZihao Yu ) 69096a786aSZihao Yu 70096a786aSZihao Yu RegMap.generate(mapping, raddr(3, 0), in.r.bits.data, 71096a786aSZihao Yu waddr(3, 0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb)) 72096a786aSZihao Yu 73096a786aSZihao Yu io.extra.get.sync := sync 748b16d276SZihao Yu } 75*226300c2Slinjiawei} 768b16d276SZihao Yu 7743002b01SZihao Yuclass FBHelper extends BlackBox with HasBlackBoxInline { 7843002b01SZihao Yu val io = IO(new Bundle { 7943002b01SZihao Yu val clk = Input(Clock()) 8043002b01SZihao Yu val valid = Input(Bool()) 8143002b01SZihao Yu val pixel = Input(UInt(32.W)) 8243002b01SZihao Yu val sync = Input(Bool()) 8343002b01SZihao Yu }) 8443002b01SZihao Yu 8543002b01SZihao Yu setInline("FBHelper.v", 8643002b01SZihao Yu s""" 8743002b01SZihao Yu |import "DPI-C" function void put_pixel(input int pixel); 8843002b01SZihao Yu |import "DPI-C" function void vmem_sync(); 8943002b01SZihao Yu | 9043002b01SZihao Yu |module FBHelper ( 9143002b01SZihao Yu | input clk, 9243002b01SZihao Yu | input valid, 9343002b01SZihao Yu | input [31:0] pixel, 9443002b01SZihao Yu | input sync 9543002b01SZihao Yu |); 9643002b01SZihao Yu | 9743002b01SZihao Yu | always@(posedge clk) begin 9843002b01SZihao Yu | if (valid) put_pixel(pixel); 9943002b01SZihao Yu | if (sync) vmem_sync(); 10043002b01SZihao Yu | end 10143002b01SZihao Yu | 10243002b01SZihao Yu |endmodule 10343002b01SZihao Yu """.stripMargin) 10443002b01SZihao Yu} 10543002b01SZihao Yu 106*226300c2Slinjiaweiclass AXI4VGA 107*226300c2Slinjiawei( 108*226300c2Slinjiawei sim: Boolean = false, 109*226300c2Slinjiawei fbAddress: AddressSet, 110*226300c2Slinjiawei ctrlAddress: AddressSet 111*226300c2Slinjiawei)(implicit p: Parameters) 112*226300c2Slinjiawei extends LazyModule with HasVGAParameter { 113*226300c2Slinjiawei 114*226300c2Slinjiawei 115*226300c2Slinjiawei private val fb = LazyModule(new AXI4RAM(fbAddress, sim, false)) 116*226300c2Slinjiawei private val ctrl = LazyModule(new VGACtrl(ctrlAddress)) 117*226300c2Slinjiawei 118*226300c2Slinjiawei val node = AXI4IdentityNode() 119*226300c2Slinjiawei 120*226300c2Slinjiawei fb.node := node 121*226300c2Slinjiawei ctrl.node := node 122*226300c2Slinjiawei 123*226300c2Slinjiawei lazy val module = new LazyModuleImp(this) { 124*226300c2Slinjiawei 125*226300c2Slinjiawei val io = IO(new Bundle() { 1268b16d276SZihao Yu val vga = new VGABundle 1278b16d276SZihao Yu }) 1288b16d276SZihao Yu 129*226300c2Slinjiawei val out_fb = node.out.head._1 130*226300c2Slinjiawei val out_ctrl = node.out.last._1 131*226300c2Slinjiawei val in_fb = node.in.head._1 132*226300c2Slinjiawei val in_ctrl = node.in.last._1 133*226300c2Slinjiawei 134*226300c2Slinjiawei in_fb.ar.ready := true.B 135*226300c2Slinjiawei in_fb.r.bits.data := 0.U 136*226300c2Slinjiawei in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY 137*226300c2Slinjiawei in_fb.r.valid := BoolStopWatch(in_fb.ar.fire(), in_fb.r.fire(), startHighPriority = true) 1388b16d276SZihao Yu 1398b16d276SZihao Yu def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 1408b16d276SZihao Yu 1418b16d276SZihao Yu val (hCounter, hFinish) = Counter(true.B, HTotal) 1428b16d276SZihao Yu val (vCounter, vFinish) = Counter(hFinish, VTotal) 1438b16d276SZihao Yu io.vga.hsync := hCounter >= HFrontPorch.U 1448b16d276SZihao Yu io.vga.vsync := vCounter >= VFrontPorch.U 1458b16d276SZihao Yu 1468b16d276SZihao Yu val hInRange = inRange(hCounter, HActive, HBackPorch) 1478b16d276SZihao Yu val vInRange = inRange(vCounter, VActive, VBackPorch) 148ec9268f7SZihao Yu io.vga.valid := hInRange && vInRange 1498b16d276SZihao Yu 1508b16d276SZihao Yu val hCounterIsOdd = hCounter(0) 1519904078bSZihao Yu val hCounterIs2 = hCounter(1, 0) === 2.U 1528b16d276SZihao Yu val vCounterIsOdd = vCounter(0) 1539904078bSZihao Yu // there is 2 cycle latency to read block memory, 1549904078bSZihao Yu // so we should issue the read request 2 cycle eariler 1558b16d276SZihao Yu val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 1568b16d276SZihao Yu val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 1578b16d276SZihao Yu val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 1588b16d276SZihao Yu 1598b16d276SZihao Yu // each pixel is 4 bytes 160*226300c2Slinjiawei out_fb.ar.bits.prot := 0.U 161*226300c2Slinjiawei out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 162*226300c2Slinjiawei out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2 1638b16d276SZihao Yu 164*226300c2Slinjiawei out_fb.r.ready := true.B 165*226300c2Slinjiawei val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire()) 1669904078bSZihao Yu val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 167ec9268f7SZihao Yu io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 16843002b01SZihao Yu 16943002b01SZihao Yu if (sim) { 17043002b01SZihao Yu val fbHelper = Module(new FBHelper) 17143002b01SZihao Yu fbHelper.io.clk := clock 172ec9268f7SZihao Yu fbHelper.io.valid := io.vga.valid 17343002b01SZihao Yu fbHelper.io.pixel := color 174*226300c2Slinjiawei fbHelper.io.sync := ctrl.module.io.extra.get.sync 17543002b01SZihao Yu } 176*226300c2Slinjiawei 177*226300c2Slinjiawei } 178*226300c2Slinjiawei 179*226300c2Slinjiawei // val AXIidBits = 2 180*226300c2Slinjiawei // val io = IO(new Bundle { 181*226300c2Slinjiawei // val in = new Bundle { 182*226300c2Slinjiawei // val fb = Flipped(new AXI4Lite) 183*226300c2Slinjiawei // val ctrl = Flipped(new AXI4Lite) 184*226300c2Slinjiawei // } 185*226300c2Slinjiawei // val vga = new VGABundle 186*226300c2Slinjiawei // }) 187*226300c2Slinjiawei // 188*226300c2Slinjiawei // val ctrl = Module(new VGACtrl) 189*226300c2Slinjiawei // io.in.ctrl <> ctrl.io.in 190*226300c2Slinjiawei // val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4)) 191*226300c2Slinjiawei // // writable by axi4lite 192*226300c2Slinjiawei // // but it only readable by the internel controller 193*226300c2Slinjiawei // fb.io.in.aw <> io.in.fb.aw 194*226300c2Slinjiawei // fb.io.in.w <> io.in.fb.w 195*226300c2Slinjiawei // io.in.fb.b <> fb.io.in.b 196*226300c2Slinjiawei // io.in.fb.ar.ready := true.B 197*226300c2Slinjiawei // io.in.fb.r.bits.data := 0.U 198*226300c2Slinjiawei // io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY 199*226300c2Slinjiawei // io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true) 200*226300c2Slinjiawei // 201*226300c2Slinjiawei // def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 202*226300c2Slinjiawei // 203*226300c2Slinjiawei // val (hCounter, hFinish) = Counter(true.B, HTotal) 204*226300c2Slinjiawei // val (vCounter, vFinish) = Counter(hFinish, VTotal) 205*226300c2Slinjiawei // 206*226300c2Slinjiawei // io.vga.hsync := hCounter >= HFrontPorch.U 207*226300c2Slinjiawei // io.vga.vsync := vCounter >= VFrontPorch.U 208*226300c2Slinjiawei // 209*226300c2Slinjiawei // val hInRange = inRange(hCounter, HActive, HBackPorch) 210*226300c2Slinjiawei // val vInRange = inRange(vCounter, VActive, VBackPorch) 211*226300c2Slinjiawei // io.vga.valid := hInRange && vInRange 212*226300c2Slinjiawei // 213*226300c2Slinjiawei // val hCounterIsOdd = hCounter(0) 214*226300c2Slinjiawei // val hCounterIs2 = hCounter(1,0) === 2.U 215*226300c2Slinjiawei // val vCounterIsOdd = vCounter(0) 216*226300c2Slinjiawei // // there is 2 cycle latency to read block memory, 217*226300c2Slinjiawei // // so we should issue the read request 2 cycle eariler 218*226300c2Slinjiawei // val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 219*226300c2Slinjiawei // val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 220*226300c2Slinjiawei // val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 221*226300c2Slinjiawei // 222*226300c2Slinjiawei // // each pixel is 4 bytes 223*226300c2Slinjiawei // fb.io.in.ar.bits.prot := 0.U 224*226300c2Slinjiawei // fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 225*226300c2Slinjiawei // fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2 226*226300c2Slinjiawei // 227*226300c2Slinjiawei // fb.io.in.r.ready := true.B 228*226300c2Slinjiawei // val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire()) 229*226300c2Slinjiawei // val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 230*226300c2Slinjiawei // io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 231*226300c2Slinjiawei // 232*226300c2Slinjiawei // if (sim) { 233*226300c2Slinjiawei // val fbHelper = Module(new FBHelper) 234*226300c2Slinjiawei // fbHelper.io.clk := clock 235*226300c2Slinjiawei // fbHelper.io.valid := io.vga.valid 236*226300c2Slinjiawei // fbHelper.io.pixel := color 237*226300c2Slinjiawei // fbHelper.io.sync := ctrl.io.extra.get.sync 238*226300c2Slinjiawei // } 2398b16d276SZihao Yu} 240