1c6d43980SLemover/*************************************************************************************** 2c6d43980SLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3f320e0f0SYinan Xu* Copyright (c) 2020-2021 Peng Cheng Laboratory 4c6d43980SLemover* 5c6d43980SLemover* XiangShan is licensed under Mulan PSL v2. 6c6d43980SLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 7c6d43980SLemover* You may obtain a copy of Mulan PSL v2 at: 8c6d43980SLemover* http://license.coscl.org.cn/MulanPSL2 9c6d43980SLemover* 10c6d43980SLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11c6d43980SLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12c6d43980SLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13c6d43980SLemover* 14c6d43980SLemover* See the Mulan PSL v2 for more details. 15c6d43980SLemover***************************************************************************************/ 16c6d43980SLemover 178b16d276SZihao Yupackage device 188b16d276SZihao Yu 198b16d276SZihao Yuimport chisel3._ 208b16d276SZihao Yuimport chisel3.util._ 21*8891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters 22510ae4eeSJiuyang Liuimport chisel3.experimental.ExtModule 23226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar} 24226300c2Slinjiaweiimport freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType} 258b16d276SZihao Yuimport utils._ 263c02ee8fSwakafaimport utility._ 278b16d276SZihao Yu 288b16d276SZihao Yutrait HasVGAConst { 298b16d276SZihao Yu val ScreenW = 800 308b16d276SZihao Yu val ScreenH = 600 318b16d276SZihao Yu 328b16d276SZihao Yu val HFrontPorch = 56 338b16d276SZihao Yu val HActive = HFrontPorch + 120 348b16d276SZihao Yu val HBackPorch = HActive + ScreenW 358b16d276SZihao Yu val HTotal = HBackPorch + 64 368b16d276SZihao Yu val VFrontPorch = 37 378b16d276SZihao Yu val VActive = VFrontPorch + 6 388b16d276SZihao Yu val VBackPorch = VActive + ScreenH 398b16d276SZihao Yu val VTotal = VBackPorch + 23 40ec9268f7SZihao Yu} 418b16d276SZihao Yu 42ec9268f7SZihao Yutrait HasHDMIConst { 43ec9268f7SZihao Yu val ScreenW = 800 44ec9268f7SZihao Yu val ScreenH = 600 45ec9268f7SZihao Yu 46ec9268f7SZihao Yu val HFrontPorch = 40 47ec9268f7SZihao Yu val HActive = HFrontPorch + 128 48ec9268f7SZihao Yu val HBackPorch = HActive + ScreenW 49ec9268f7SZihao Yu val HTotal = HBackPorch + 88 50ec9268f7SZihao Yu val VFrontPorch = 1 51ec9268f7SZihao Yu val VActive = VFrontPorch + 4 52ec9268f7SZihao Yu val VBackPorch = VActive + ScreenH 53ec9268f7SZihao Yu val VTotal = VBackPorch + 23 54ec9268f7SZihao Yu} 55ec9268f7SZihao Yu 56ec9268f7SZihao Yutrait HasVGAParameter extends HasHDMIConst { 578b16d276SZihao Yu val FBWidth = ScreenW / 2 588b16d276SZihao Yu val FBHeight = ScreenH / 2 598b16d276SZihao Yu val FBPixels = FBWidth * FBHeight 608b16d276SZihao Yu} 618b16d276SZihao Yu 628b16d276SZihao Yuclass VGABundle extends Bundle { 63ec9268f7SZihao Yu val rgb = Output(UInt(24.W)) 648b16d276SZihao Yu val hsync = Output(Bool()) 658b16d276SZihao Yu val vsync = Output(Bool()) 66ec9268f7SZihao Yu val valid = Output(Bool()) 678b16d276SZihao Yu} 688b16d276SZihao Yu 69096a786aSZihao Yuclass VGACtrlBundle extends Bundle { 70096a786aSZihao Yu val sync = Output(Bool()) 71096a786aSZihao Yu} 72096a786aSZihao Yu 73226300c2Slinjiaweiclass VGACtrl 74226300c2Slinjiawei( 75a2e9bde6SAllen address: Seq[AddressSet] 76226300c2Slinjiawei)(implicit p: Parameters) 77226300c2Slinjiawei extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter { 78226300c2Slinjiawei override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) { 79226300c2Slinjiawei 808b16d276SZihao Yu val fbSizeReg = Cat(FBWidth.U(16.W), FBHeight.U(16.W)) 81935edac4STang Haojin val sync = in.aw.fire 82096a786aSZihao Yu 83096a786aSZihao Yu val mapping = Map( 84096a786aSZihao Yu RegMap(0x0, fbSizeReg, RegMap.Unwritable), 85096a786aSZihao Yu RegMap(0x4, sync, RegMap.Unwritable) 86096a786aSZihao Yu ) 87096a786aSZihao Yu 88096a786aSZihao Yu RegMap.generate(mapping, raddr(3, 0), in.r.bits.data, 89935edac4STang Haojin waddr(3, 0), in.w.fire, in.w.bits.data, MaskExpand(in.w.bits.strb)) 90096a786aSZihao Yu 91096a786aSZihao Yu io.extra.get.sync := sync 928b16d276SZihao Yu } 93226300c2Slinjiawei} 948b16d276SZihao Yu 95510ae4eeSJiuyang Liuclass FBHelper extends ExtModule with HasExtModuleInline { 96510ae4eeSJiuyang Liu val clk = IO(Input(Clock())) 97510ae4eeSJiuyang Liu val valid = IO(Input(Bool())) 98510ae4eeSJiuyang Liu val pixel = IO(Input(UInt(32.W))) 99510ae4eeSJiuyang Liu val sync = IO(Input(Bool())) 10043002b01SZihao Yu 10143002b01SZihao Yu setInline("FBHelper.v", 10243002b01SZihao Yu s""" 10343002b01SZihao Yu |import "DPI-C" function void put_pixel(input int pixel); 10443002b01SZihao Yu |import "DPI-C" function void vmem_sync(); 10543002b01SZihao Yu | 10643002b01SZihao Yu |module FBHelper ( 10743002b01SZihao Yu | input clk, 10843002b01SZihao Yu | input valid, 10943002b01SZihao Yu | input [31:0] pixel, 11043002b01SZihao Yu | input sync 11143002b01SZihao Yu |); 11243002b01SZihao Yu | 11343002b01SZihao Yu | always@(posedge clk) begin 11443002b01SZihao Yu | if (valid) put_pixel(pixel); 11543002b01SZihao Yu | if (sync) vmem_sync(); 11643002b01SZihao Yu | end 11743002b01SZihao Yu | 11843002b01SZihao Yu |endmodule 11943002b01SZihao Yu """.stripMargin) 12043002b01SZihao Yu} 12143002b01SZihao Yu 122226300c2Slinjiaweiclass AXI4VGA 123226300c2Slinjiawei( 124226300c2Slinjiawei sim: Boolean = false, 125a2e9bde6SAllen fbAddress: Seq[AddressSet], 126a2e9bde6SAllen ctrlAddress: Seq[AddressSet] 127226300c2Slinjiawei)(implicit p: Parameters) 128226300c2Slinjiawei extends LazyModule with HasVGAParameter { 129226300c2Slinjiawei 130226300c2Slinjiawei 1316f1f3ac7Slinjiawei private val fb = LazyModule(new AXI4RAM( 1326f1f3ac7Slinjiawei fbAddress, 1336f1f3ac7Slinjiawei memByte= FBPixels * 4, 1346f1f3ac7Slinjiawei sim, 1356f1f3ac7Slinjiawei executable = false 1366f1f3ac7Slinjiawei )) 137226300c2Slinjiawei private val ctrl = LazyModule(new VGACtrl(ctrlAddress)) 138226300c2Slinjiawei 139226300c2Slinjiawei val node = AXI4IdentityNode() 140226300c2Slinjiawei 141226300c2Slinjiawei fb.node := node 142226300c2Slinjiawei ctrl.node := node 143226300c2Slinjiawei 144226300c2Slinjiawei lazy val module = new LazyModuleImp(this) { 145226300c2Slinjiawei 146226300c2Slinjiawei val io = IO(new Bundle() { 1478b16d276SZihao Yu val vga = new VGABundle 1488b16d276SZihao Yu }) 1498b16d276SZihao Yu 150226300c2Slinjiawei val out_fb = node.out.head._1 151226300c2Slinjiawei val out_ctrl = node.out.last._1 152226300c2Slinjiawei val in_fb = node.in.head._1 153226300c2Slinjiawei val in_ctrl = node.in.last._1 154226300c2Slinjiawei 155226300c2Slinjiawei in_fb.ar.ready := true.B 156226300c2Slinjiawei in_fb.r.bits.data := 0.U 157226300c2Slinjiawei in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY 158935edac4STang Haojin in_fb.r.valid := BoolStopWatch(in_fb.ar.fire, in_fb.r.fire, startHighPriority = true) 1598b16d276SZihao Yu 1608b16d276SZihao Yu def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 1618b16d276SZihao Yu 1628b16d276SZihao Yu val (hCounter, hFinish) = Counter(true.B, HTotal) 1638b16d276SZihao Yu val (vCounter, vFinish) = Counter(hFinish, VTotal) 1648b16d276SZihao Yu io.vga.hsync := hCounter >= HFrontPorch.U 1658b16d276SZihao Yu io.vga.vsync := vCounter >= VFrontPorch.U 1668b16d276SZihao Yu 1678b16d276SZihao Yu val hInRange = inRange(hCounter, HActive, HBackPorch) 1688b16d276SZihao Yu val vInRange = inRange(vCounter, VActive, VBackPorch) 169ec9268f7SZihao Yu io.vga.valid := hInRange && vInRange 1708b16d276SZihao Yu 1718b16d276SZihao Yu val hCounterIsOdd = hCounter(0) 1729904078bSZihao Yu val hCounterIs2 = hCounter(1, 0) === 2.U 1738b16d276SZihao Yu val vCounterIsOdd = vCounter(0) 1749904078bSZihao Yu // there is 2 cycle latency to read block memory, 1759904078bSZihao Yu // so we should issue the read request 2 cycle eariler 1768b16d276SZihao Yu val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 1778b16d276SZihao Yu val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 1788b16d276SZihao Yu val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 1798b16d276SZihao Yu 1808b16d276SZihao Yu // each pixel is 4 bytes 181226300c2Slinjiawei out_fb.ar.bits.prot := 0.U 182226300c2Slinjiawei out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 183226300c2Slinjiawei out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2 1848b16d276SZihao Yu 185226300c2Slinjiawei out_fb.r.ready := true.B 186935edac4STang Haojin val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire) 1879904078bSZihao Yu val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 188ec9268f7SZihao Yu io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 18943002b01SZihao Yu 19043002b01SZihao Yu if (sim) { 19143002b01SZihao Yu val fbHelper = Module(new FBHelper) 192510ae4eeSJiuyang Liu fbHelper.clk := clock 193510ae4eeSJiuyang Liu fbHelper.valid := io.vga.valid 194510ae4eeSJiuyang Liu fbHelper.pixel := color 195510ae4eeSJiuyang Liu fbHelper.sync := ctrl.module.io.extra.get.sync 19643002b01SZihao Yu } 197226300c2Slinjiawei 198226300c2Slinjiawei } 199226300c2Slinjiawei 200226300c2Slinjiawei // val AXIidBits = 2 201226300c2Slinjiawei // val io = IO(new Bundle { 202226300c2Slinjiawei // val in = new Bundle { 203226300c2Slinjiawei // val fb = Flipped(new AXI4Lite) 204226300c2Slinjiawei // val ctrl = Flipped(new AXI4Lite) 205226300c2Slinjiawei // } 206226300c2Slinjiawei // val vga = new VGABundle 207226300c2Slinjiawei // }) 208226300c2Slinjiawei // 209226300c2Slinjiawei // val ctrl = Module(new VGACtrl) 210226300c2Slinjiawei // io.in.ctrl <> ctrl.io.in 211226300c2Slinjiawei // val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4)) 212226300c2Slinjiawei // // writable by axi4lite 213226300c2Slinjiawei // // but it only readable by the internel controller 214226300c2Slinjiawei // fb.io.in.aw <> io.in.fb.aw 215226300c2Slinjiawei // fb.io.in.w <> io.in.fb.w 216226300c2Slinjiawei // io.in.fb.b <> fb.io.in.b 217226300c2Slinjiawei // io.in.fb.ar.ready := true.B 218226300c2Slinjiawei // io.in.fb.r.bits.data := 0.U 219226300c2Slinjiawei // io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY 220935edac4STang Haojin // io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire, io.in.fb.r.fire, startHighPriority = true) 221226300c2Slinjiawei // 222226300c2Slinjiawei // def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 223226300c2Slinjiawei // 224226300c2Slinjiawei // val (hCounter, hFinish) = Counter(true.B, HTotal) 225226300c2Slinjiawei // val (vCounter, vFinish) = Counter(hFinish, VTotal) 226226300c2Slinjiawei // 227226300c2Slinjiawei // io.vga.hsync := hCounter >= HFrontPorch.U 228226300c2Slinjiawei // io.vga.vsync := vCounter >= VFrontPorch.U 229226300c2Slinjiawei // 230226300c2Slinjiawei // val hInRange = inRange(hCounter, HActive, HBackPorch) 231226300c2Slinjiawei // val vInRange = inRange(vCounter, VActive, VBackPorch) 232226300c2Slinjiawei // io.vga.valid := hInRange && vInRange 233226300c2Slinjiawei // 234226300c2Slinjiawei // val hCounterIsOdd = hCounter(0) 235226300c2Slinjiawei // val hCounterIs2 = hCounter(1,0) === 2.U 236226300c2Slinjiawei // val vCounterIsOdd = vCounter(0) 237226300c2Slinjiawei // // there is 2 cycle latency to read block memory, 238226300c2Slinjiawei // // so we should issue the read request 2 cycle eariler 239226300c2Slinjiawei // val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 240226300c2Slinjiawei // val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 241226300c2Slinjiawei // val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 242226300c2Slinjiawei // 243226300c2Slinjiawei // // each pixel is 4 bytes 244226300c2Slinjiawei // fb.io.in.ar.bits.prot := 0.U 245226300c2Slinjiawei // fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 246226300c2Slinjiawei // fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2 247226300c2Slinjiawei // 248226300c2Slinjiawei // fb.io.in.r.ready := true.B 249935edac4STang Haojin // val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire) 250226300c2Slinjiawei // val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 251226300c2Slinjiawei // io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 252226300c2Slinjiawei // 253226300c2Slinjiawei // if (sim) { 254226300c2Slinjiawei // val fbHelper = Module(new FBHelper) 255226300c2Slinjiawei // fbHelper.io.clk := clock 256226300c2Slinjiawei // fbHelper.io.valid := io.vga.valid 257226300c2Slinjiawei // fbHelper.io.pixel := color 258226300c2Slinjiawei // fbHelper.io.sync := ctrl.io.extra.get.sync 259226300c2Slinjiawei // } 2608b16d276SZihao Yu} 261