18b16d276SZihao Yupackage device 28b16d276SZihao Yu 38b16d276SZihao Yuimport chisel3._ 48b16d276SZihao Yuimport chisel3.util._ 5226300c2Slinjiaweiimport chipsalliance.rocketchip.config.Parameters 6226300c2Slinjiaweiimport freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar} 7226300c2Slinjiaweiimport 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 55226300c2Slinjiaweiclass VGACtrl 56226300c2Slinjiawei( 57*a2e9bde6SAllen address: Seq[AddressSet] 58226300c2Slinjiawei)(implicit p: Parameters) 59226300c2Slinjiawei extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter { 60226300c2Slinjiawei override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) { 61226300c2Slinjiawei 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 } 75226300c2Slinjiawei} 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 106226300c2Slinjiaweiclass AXI4VGA 107226300c2Slinjiawei( 108226300c2Slinjiawei sim: Boolean = false, 109*a2e9bde6SAllen fbAddress: Seq[AddressSet], 110*a2e9bde6SAllen ctrlAddress: Seq[AddressSet] 111226300c2Slinjiawei)(implicit p: Parameters) 112226300c2Slinjiawei extends LazyModule with HasVGAParameter { 113226300c2Slinjiawei 114226300c2Slinjiawei 1156f1f3ac7Slinjiawei private val fb = LazyModule(new AXI4RAM( 1166f1f3ac7Slinjiawei fbAddress, 1176f1f3ac7Slinjiawei memByte= FBPixels * 4, 1186f1f3ac7Slinjiawei sim, 1196f1f3ac7Slinjiawei executable = false 1206f1f3ac7Slinjiawei )) 121226300c2Slinjiawei private val ctrl = LazyModule(new VGACtrl(ctrlAddress)) 122226300c2Slinjiawei 123226300c2Slinjiawei val node = AXI4IdentityNode() 124226300c2Slinjiawei 125226300c2Slinjiawei fb.node := node 126226300c2Slinjiawei ctrl.node := node 127226300c2Slinjiawei 128226300c2Slinjiawei lazy val module = new LazyModuleImp(this) { 129226300c2Slinjiawei 130226300c2Slinjiawei val io = IO(new Bundle() { 1318b16d276SZihao Yu val vga = new VGABundle 1328b16d276SZihao Yu }) 1338b16d276SZihao Yu 134226300c2Slinjiawei val out_fb = node.out.head._1 135226300c2Slinjiawei val out_ctrl = node.out.last._1 136226300c2Slinjiawei val in_fb = node.in.head._1 137226300c2Slinjiawei val in_ctrl = node.in.last._1 138226300c2Slinjiawei 139226300c2Slinjiawei in_fb.ar.ready := true.B 140226300c2Slinjiawei in_fb.r.bits.data := 0.U 141226300c2Slinjiawei in_fb.r.bits.resp := AXI4Parameters.RESP_OKAY 142226300c2Slinjiawei in_fb.r.valid := BoolStopWatch(in_fb.ar.fire(), in_fb.r.fire(), startHighPriority = true) 1438b16d276SZihao Yu 1448b16d276SZihao Yu def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 1458b16d276SZihao Yu 1468b16d276SZihao Yu val (hCounter, hFinish) = Counter(true.B, HTotal) 1478b16d276SZihao Yu val (vCounter, vFinish) = Counter(hFinish, VTotal) 1488b16d276SZihao Yu io.vga.hsync := hCounter >= HFrontPorch.U 1498b16d276SZihao Yu io.vga.vsync := vCounter >= VFrontPorch.U 1508b16d276SZihao Yu 1518b16d276SZihao Yu val hInRange = inRange(hCounter, HActive, HBackPorch) 1528b16d276SZihao Yu val vInRange = inRange(vCounter, VActive, VBackPorch) 153ec9268f7SZihao Yu io.vga.valid := hInRange && vInRange 1548b16d276SZihao Yu 1558b16d276SZihao Yu val hCounterIsOdd = hCounter(0) 1569904078bSZihao Yu val hCounterIs2 = hCounter(1, 0) === 2.U 1578b16d276SZihao Yu val vCounterIsOdd = vCounter(0) 1589904078bSZihao Yu // there is 2 cycle latency to read block memory, 1599904078bSZihao Yu // so we should issue the read request 2 cycle eariler 1608b16d276SZihao Yu val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 1618b16d276SZihao Yu val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 1628b16d276SZihao Yu val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 1638b16d276SZihao Yu 1648b16d276SZihao Yu // each pixel is 4 bytes 165226300c2Slinjiawei out_fb.ar.bits.prot := 0.U 166226300c2Slinjiawei out_fb.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 167226300c2Slinjiawei out_fb.ar.valid := RegNext(nextPixel) && hCounterIs2 1688b16d276SZihao Yu 169226300c2Slinjiawei out_fb.r.ready := true.B 170226300c2Slinjiawei val data = HoldUnless(out_fb.r.bits.data, out_fb.r.fire()) 1719904078bSZihao Yu val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 172ec9268f7SZihao Yu io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 17343002b01SZihao Yu 17443002b01SZihao Yu if (sim) { 17543002b01SZihao Yu val fbHelper = Module(new FBHelper) 17643002b01SZihao Yu fbHelper.io.clk := clock 177ec9268f7SZihao Yu fbHelper.io.valid := io.vga.valid 17843002b01SZihao Yu fbHelper.io.pixel := color 179226300c2Slinjiawei fbHelper.io.sync := ctrl.module.io.extra.get.sync 18043002b01SZihao Yu } 181226300c2Slinjiawei 182226300c2Slinjiawei } 183226300c2Slinjiawei 184226300c2Slinjiawei // val AXIidBits = 2 185226300c2Slinjiawei // val io = IO(new Bundle { 186226300c2Slinjiawei // val in = new Bundle { 187226300c2Slinjiawei // val fb = Flipped(new AXI4Lite) 188226300c2Slinjiawei // val ctrl = Flipped(new AXI4Lite) 189226300c2Slinjiawei // } 190226300c2Slinjiawei // val vga = new VGABundle 191226300c2Slinjiawei // }) 192226300c2Slinjiawei // 193226300c2Slinjiawei // val ctrl = Module(new VGACtrl) 194226300c2Slinjiawei // io.in.ctrl <> ctrl.io.in 195226300c2Slinjiawei // val fb = Module(new AXI4RAM(new AXI4Lite, memByte = FBPixels * 4)) 196226300c2Slinjiawei // // writable by axi4lite 197226300c2Slinjiawei // // but it only readable by the internel controller 198226300c2Slinjiawei // fb.io.in.aw <> io.in.fb.aw 199226300c2Slinjiawei // fb.io.in.w <> io.in.fb.w 200226300c2Slinjiawei // io.in.fb.b <> fb.io.in.b 201226300c2Slinjiawei // io.in.fb.ar.ready := true.B 202226300c2Slinjiawei // io.in.fb.r.bits.data := 0.U 203226300c2Slinjiawei // io.in.fb.r.bits.resp := AXI4Parameters.RESP_OKAY 204226300c2Slinjiawei // io.in.fb.r.valid := BoolStopWatch(io.in.fb.ar.fire(), io.in.fb.r.fire(), startHighPriority = true) 205226300c2Slinjiawei // 206226300c2Slinjiawei // def inRange(x: UInt, start: Int, end: Int) = (x >= start.U) && (x < end.U) 207226300c2Slinjiawei // 208226300c2Slinjiawei // val (hCounter, hFinish) = Counter(true.B, HTotal) 209226300c2Slinjiawei // val (vCounter, vFinish) = Counter(hFinish, VTotal) 210226300c2Slinjiawei // 211226300c2Slinjiawei // io.vga.hsync := hCounter >= HFrontPorch.U 212226300c2Slinjiawei // io.vga.vsync := vCounter >= VFrontPorch.U 213226300c2Slinjiawei // 214226300c2Slinjiawei // val hInRange = inRange(hCounter, HActive, HBackPorch) 215226300c2Slinjiawei // val vInRange = inRange(vCounter, VActive, VBackPorch) 216226300c2Slinjiawei // io.vga.valid := hInRange && vInRange 217226300c2Slinjiawei // 218226300c2Slinjiawei // val hCounterIsOdd = hCounter(0) 219226300c2Slinjiawei // val hCounterIs2 = hCounter(1,0) === 2.U 220226300c2Slinjiawei // val vCounterIsOdd = vCounter(0) 221226300c2Slinjiawei // // there is 2 cycle latency to read block memory, 222226300c2Slinjiawei // // so we should issue the read request 2 cycle eariler 223226300c2Slinjiawei // val nextPixel = inRange(hCounter, HActive - 1, HBackPorch - 1) && vInRange && hCounterIsOdd 224226300c2Slinjiawei // val fbPixelAddrV0 = Counter(nextPixel && !vCounterIsOdd, FBPixels)._1 225226300c2Slinjiawei // val fbPixelAddrV1 = Counter(nextPixel && vCounterIsOdd, FBPixels)._1 226226300c2Slinjiawei // 227226300c2Slinjiawei // // each pixel is 4 bytes 228226300c2Slinjiawei // fb.io.in.ar.bits.prot := 0.U 229226300c2Slinjiawei // fb.io.in.ar.bits.addr := Cat(Mux(vCounterIsOdd, fbPixelAddrV1, fbPixelAddrV0), 0.U(2.W)) 230226300c2Slinjiawei // fb.io.in.ar.valid := RegNext(nextPixel) && hCounterIs2 231226300c2Slinjiawei // 232226300c2Slinjiawei // fb.io.in.r.ready := true.B 233226300c2Slinjiawei // val data = HoldUnless(fb.io.in.r.bits.data, fb.io.in.r.fire()) 234226300c2Slinjiawei // val color = Mux(hCounter(1), data(63, 32), data(31, 0)) 235226300c2Slinjiawei // io.vga.rgb := Mux(io.vga.valid, color(23, 0), 0.U) 236226300c2Slinjiawei // 237226300c2Slinjiawei // if (sim) { 238226300c2Slinjiawei // val fbHelper = Module(new FBHelper) 239226300c2Slinjiawei // fbHelper.io.clk := clock 240226300c2Slinjiawei // fbHelper.io.valid := io.vga.valid 241226300c2Slinjiawei // fbHelper.io.pixel := color 242226300c2Slinjiawei // fbHelper.io.sync := ctrl.io.extra.get.sync 243226300c2Slinjiawei // } 2448b16d276SZihao Yu} 245