1*c6d43980SLemover/*************************************************************************************** 2*c6d43980SLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*c6d43980SLemover* 4*c6d43980SLemover* XiangShan is licensed under Mulan PSL v2. 5*c6d43980SLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 6*c6d43980SLemover* You may obtain a copy of Mulan PSL v2 at: 7*c6d43980SLemover* http://license.coscl.org.cn/MulanPSL2 8*c6d43980SLemover* 9*c6d43980SLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10*c6d43980SLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11*c6d43980SLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12*c6d43980SLemover* 13*c6d43980SLemover* See the Mulan PSL v2 for more details. 14*c6d43980SLemover***************************************************************************************/ 15*c6d43980SLemover 168b16d276SZihao Yupackage device 178b16d276SZihao Yu 188b16d276SZihao Yuimport chisel3._ 198b16d276SZihao Yuimport chisel3.util._ 20226300c2Slinjiaweiimport chipsalliance.rocketchip.config.Parameters 21226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar} 22226300c2Slinjiaweiimport freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType} 238b16d276SZihao Yuimport utils._ 248b16d276SZihao Yu 258b16d276SZihao Yutrait HasVGAConst { 268b16d276SZihao Yu val ScreenW = 800 278b16d276SZihao Yu val ScreenH = 600 288b16d276SZihao Yu 298b16d276SZihao Yu val HFrontPorch = 56 308b16d276SZihao Yu val HActive = HFrontPorch + 120 318b16d276SZihao Yu val HBackPorch = HActive + ScreenW 328b16d276SZihao Yu val HTotal = HBackPorch + 64 338b16d276SZihao Yu val VFrontPorch = 37 348b16d276SZihao Yu val VActive = VFrontPorch + 6 358b16d276SZihao Yu val VBackPorch = VActive + ScreenH 368b16d276SZihao Yu val VTotal = VBackPorch + 23 37ec9268f7SZihao Yu} 388b16d276SZihao Yu 39ec9268f7SZihao Yutrait HasHDMIConst { 40ec9268f7SZihao Yu val ScreenW = 800 41ec9268f7SZihao Yu val ScreenH = 600 42ec9268f7SZihao Yu 43ec9268f7SZihao Yu val HFrontPorch = 40 44ec9268f7SZihao Yu val HActive = HFrontPorch + 128 45ec9268f7SZihao Yu val HBackPorch = HActive + ScreenW 46ec9268f7SZihao Yu val HTotal = HBackPorch + 88 47ec9268f7SZihao Yu val VFrontPorch = 1 48ec9268f7SZihao Yu val VActive = VFrontPorch + 4 49ec9268f7SZihao Yu val VBackPorch = VActive + ScreenH 50ec9268f7SZihao Yu val VTotal = VBackPorch + 23 51ec9268f7SZihao Yu} 52ec9268f7SZihao Yu 53ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst { 548b16d276SZihao Yu val FBWidth = ScreenW / 2 558b16d276SZihao Yu val FBHeight = ScreenH / 2 568b16d276SZihao Yu val FBPixels = FBWidth * FBHeight 578b16d276SZihao Yu} 588b16d276SZihao Yu 598b16d276SZihao Yuclass VGABundle extends Bundle { 60ec9268f7SZihao Yu val rgb = Output(UInt(24.W)) 618b16d276SZihao Yu val hsync = Output(Bool()) 628b16d276SZihao Yu val vsync = Output(Bool()) 63ec9268f7SZihao Yu val valid = Output(Bool()) 648b16d276SZihao Yu} 658b16d276SZihao Yu 66096a786aSZihao Yuclass VGACtrlBundle extends Bundle { 67096a786aSZihao Yu val sync = Output(Bool()) 68096a786aSZihao Yu} 69096a786aSZihao Yu 70226300c2Slinjiaweiclass VGACtrl 71226300c2Slinjiawei( 72a2e9bde6SAllen address: Seq[AddressSet] 73226300c2Slinjiawei)(implicit p: Parameters) 74226300c2Slinjiawei extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter { 75226300c2Slinjiawei override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) { 76226300c2Slinjiawei 778b16d276SZihao Yu val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W)) 788b16d276SZihao Yu val sync = in.aw.fire() 79096a786aSZihao Yu 80096a786aSZihao Yu val mapping = Map( 81096a786aSZihao Yu RegMap(0x0, fbSizeReg, RegMap.Unwritable), 82096a786aSZihao Yu RegMap(0x4, sync, RegMap.Unwritable) 83096a786aSZihao Yu ) 84096a786aSZihao Yu 85096a786aSZihao Yu RegMap.generate(mapping, raddr(3, 0), in.r.bits.data, 86096a786aSZihao Yu waddr(3, 0), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb)) 87096a786aSZihao Yu 88096a786aSZihao Yu io.extra.get.sync := sync 898b16d276SZihao Yu } 90226300c2Slinjiawei} 918b16d276SZihao Yu 9243002b01SZihao Yuclass FBHelper extends BlackBox with HasBlackBoxInline { 9343002b01SZihao Yu val io = IO(new Bundle { 9443002b01SZihao Yu val clk = Input(Clock()) 9543002b01SZihao Yu val valid = Input(Bool()) 9643002b01SZihao Yu val pixel = Input(UInt(32.W)) 9743002b01SZihao Yu val sync = Input(Bool()) 9843002b01SZihao Yu }) 9943002b01SZihao Yu 10043002b01SZihao Yu setInline("FBHelper.v", 10143002b01SZihao Yu s""" 10243002b01SZihao Yu |import "DPI-C" function void put_pixel(input int pixel); 10343002b01SZihao Yu |import "DPI-C" function void vmem_sync(); 10443002b01SZihao Yu | 10543002b01SZihao Yu |module FBHelper ( 10643002b01SZihao Yu | input clk, 10743002b01SZihao Yu | input valid, 10843002b01SZihao Yu | input [31:0] pixel, 10943002b01SZihao Yu | input sync 11043002b01SZihao Yu |); 11143002b01SZihao Yu | 11243002b01SZihao Yu | always@(posedge clk) begin 11343002b01SZihao Yu | if (valid) put_pixel(pixel); 11443002b01SZihao Yu | if (sync) vmem_sync(); 11543002b01SZihao Yu | end 11643002b01SZihao Yu | 11743002b01SZihao Yu |endmodule 11843002b01SZihao Yu """.stripMargin) 11943002b01SZihao Yu} 12043002b01SZihao Yu 121226300c2Slinjiaweiclass AXI4VGA 122226300c2Slinjiawei( 123226300c2Slinjiawei sim: Boolean = false, 124a2e9bde6SAllen fbAddress: Seq[AddressSet], 125a2e9bde6SAllen ctrlAddress: Seq[AddressSet] 126226300c2Slinjiawei)(implicit p: Parameters) 127226300c2Slinjiawei extends LazyModule with HasVGAParameter { 128226300c2Slinjiawei 129226300c2Slinjiawei 1306f1f3ac7Slinjiawei private val fb = LazyModule(new AXI4RAM( 1316f1f3ac7Slinjiawei fbAddress, 1326f1f3ac7Slinjiawei memByte= FBPixels * 4, 1336f1f3ac7Slinjiawei sim, 1346f1f3ac7Slinjiawei executable = false 1356f1f3ac7Slinjiawei )) 136226300c2Slinjiawei private val ctrl = LazyModule(new VGACtrl(ctrlAddress)) 137226300c2Slinjiawei 138226300c2Slinjiawei val node = AXI4IdentityNode() 139226300c2Slinjiawei 140226300c2Slinjiawei fb.node := node 141226300c2Slinjiawei ctrl.node := node 142226300c2Slinjiawei 143226300c2Slinjiawei lazy val module = new LazyModuleImp(this) { 144226300c2Slinjiawei 145226300c2Slinjiawei val io = IO(new Bundle() { 1468b16d276SZihao Yu val vga = new VGABundle 1478b16d276SZihao Yu }) 1488b16d276SZihao Yu 149226300c2Slinjiawei val out_fb = node.out.head._1 150226300c2Slinjiawei val out_ctrl = node.out.last._1 151226300c2Slinjiawei val in_fb = node.in.head._1 152226300c2Slinjiawei val in_ctrl = node.in.last._1 153226300c2Slinjiawei 154226300c2Slinjiawei in_fb.ar.ready := true.B 155226300c2Slinjiawei in_fb.r.bits.data := 0.U 156226300c2Slinjiawei in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY 157226300c2Slinjiawei in_fb.r.valid := BoolStopWatch(in_fb.ar.fire(), in_fb.r.fire(), startHighPriority = true) 1588b16d276SZihao Yu 1598b16d276SZihao Yu def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 1608b16d276SZihao Yu 1618b16d276SZihao Yu val (hCounter, hFinish) = Counter(true.B, HTotal) 1628b16d276SZihao Yu val (vCounter, vFinish) = Counter(hFinish, VTotal) 1638b16d276SZihao Yu io.vga.hsync := hCounter >= HFrontPorch.U 1648b16d276SZihao Yu io.vga.vsync := vCounter >= VFrontPorch.U 1658b16d276SZihao Yu 1668b16d276SZihao Yu val hInRange = inRange(hCounter, HActive, HBackPorch) 1678b16d276SZihao Yu val vInRange = inRange(vCounter, VActive, VBackPorch) 168ec9268f7SZihao Yu io.vga.valid := hInRange && vInRange 1698b16d276SZihao Yu 1708b16d276SZihao Yu val hCounterIsOdd = hCounter(0) 1719904078bSZihao Yu val hCounterIs2 = hCounter(1, 0) === 2.U 1728b16d276SZihao Yu val vCounterIsOdd = vCounter(0) 1739904078bSZihao Yu // there is 2 cycle latency to read block memory, 1749904078bSZihao Yu // so we should issue the read request 2 cycle eariler 1758b16d276SZihao Yu val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 1768b16d276SZihao Yu val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 1778b16d276SZihao Yu val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 1788b16d276SZihao Yu 1798b16d276SZihao Yu // each pixel is 4 bytes 180226300c2Slinjiawei out_fb.ar.bits.prot := 0.U 181226300c2Slinjiawei out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 182226300c2Slinjiawei out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2 1838b16d276SZihao Yu 184226300c2Slinjiawei out_fb.r.ready := true.B 185226300c2Slinjiawei val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire()) 1869904078bSZihao Yu val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 187ec9268f7SZihao Yu io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 18843002b01SZihao Yu 18943002b01SZihao Yu if (sim) { 19043002b01SZihao Yu val fbHelper = Module(new FBHelper) 19143002b01SZihao Yu fbHelper.io.clk := clock 192ec9268f7SZihao Yu fbHelper.io.valid := io.vga.valid 19343002b01SZihao Yu fbHelper.io.pixel := color 194226300c2Slinjiawei fbHelper.io.sync := ctrl.module.io.extra.get.sync 19543002b01SZihao Yu } 196226300c2Slinjiawei 197226300c2Slinjiawei } 198226300c2Slinjiawei 199226300c2Slinjiawei // val AXIidBits = 2 200226300c2Slinjiawei // val io = IO(new Bundle { 201226300c2Slinjiawei // val in = new Bundle { 202226300c2Slinjiawei // val fb = Flipped(new AXI4Lite) 203226300c2Slinjiawei // val ctrl = Flipped(new AXI4Lite) 204226300c2Slinjiawei // } 205226300c2Slinjiawei // val vga = new VGABundle 206226300c2Slinjiawei // }) 207226300c2Slinjiawei // 208226300c2Slinjiawei // val ctrl = Module(new VGACtrl) 209226300c2Slinjiawei // io.in.ctrl <> ctrl.io.in 210226300c2Slinjiawei // val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4)) 211226300c2Slinjiawei // // writable by axi4lite 212226300c2Slinjiawei // // but it only readable by the internel controller 213226300c2Slinjiawei // fb.io.in.aw <> io.in.fb.aw 214226300c2Slinjiawei // fb.io.in.w <> io.in.fb.w 215226300c2Slinjiawei // io.in.fb.b <> fb.io.in.b 216226300c2Slinjiawei // io.in.fb.ar.ready := true.B 217226300c2Slinjiawei // io.in.fb.r.bits.data := 0.U 218226300c2Slinjiawei // io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY 219226300c2Slinjiawei // io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true) 220226300c2Slinjiawei // 221226300c2Slinjiawei // def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 222226300c2Slinjiawei // 223226300c2Slinjiawei // val (hCounter, hFinish) = Counter(true.B, HTotal) 224226300c2Slinjiawei // val (vCounter, vFinish) = Counter(hFinish, VTotal) 225226300c2Slinjiawei // 226226300c2Slinjiawei // io.vga.hsync := hCounter >= HFrontPorch.U 227226300c2Slinjiawei // io.vga.vsync := vCounter >= VFrontPorch.U 228226300c2Slinjiawei // 229226300c2Slinjiawei // val hInRange = inRange(hCounter, HActive, HBackPorch) 230226300c2Slinjiawei // val vInRange = inRange(vCounter, VActive, VBackPorch) 231226300c2Slinjiawei // io.vga.valid := hInRange && vInRange 232226300c2Slinjiawei // 233226300c2Slinjiawei // val hCounterIsOdd = hCounter(0) 234226300c2Slinjiawei // val hCounterIs2 = hCounter(1,0) === 2.U 235226300c2Slinjiawei // val vCounterIsOdd = vCounter(0) 236226300c2Slinjiawei // // there is 2 cycle latency to read block memory, 237226300c2Slinjiawei // // so we should issue the read request 2 cycle eariler 238226300c2Slinjiawei // val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 239226300c2Slinjiawei // val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 240226300c2Slinjiawei // val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 241226300c2Slinjiawei // 242226300c2Slinjiawei // // each pixel is 4 bytes 243226300c2Slinjiawei // fb.io.in.ar.bits.prot := 0.U 244226300c2Slinjiawei // fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 245226300c2Slinjiawei // fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2 246226300c2Slinjiawei // 247226300c2Slinjiawei // fb.io.in.r.ready := true.B 248226300c2Slinjiawei // val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire()) 249226300c2Slinjiawei // val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 250226300c2Slinjiawei // io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 251226300c2Slinjiawei // 252226300c2Slinjiawei // if (sim) { 253226300c2Slinjiawei // val fbHelper = Module(new FBHelper) 254226300c2Slinjiawei // fbHelper.io.clk := clock 255226300c2Slinjiawei // fbHelper.io.valid := io.vga.valid 256226300c2Slinjiawei // fbHelper.io.pixel := color 257226300c2Slinjiawei // fbHelper.io.sync := ctrl.io.extra.get.sync 258226300c2Slinjiawei // } 2598b16d276SZihao Yu} 260