1 // 2 // Copyright (c) 2010 - 2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.Linq; 10 using Antmicro.Renode.Backends.Display; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Peripherals.Memory; 16 using Antmicro.Renode.Utilities; 17 18 namespace Antmicro.Renode.Peripherals.Video 19 { 20 public class LiteX_Framebuffer : AutoRepaintingVideo, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 21 { LiteX_Framebuffer(IMachine machine, PixelFormat format, IBusPeripheral memory)22 public LiteX_Framebuffer(IMachine machine, PixelFormat format, IBusPeripheral memory) : base(machine) 23 { 24 this.memory = memory; 25 sysbus = machine.GetSystemBus(this); 26 this.format = format; 27 28 RegistersCollection = new DoubleWordRegisterCollection(this); 29 DefineRegisters(); 30 } 31 WriteDoubleWord(long address, uint value)32 public void WriteDoubleWord(long address, uint value) 33 { 34 RegistersCollection.Write(address, value); 35 } 36 ReadDoubleWord(long offset)37 public uint ReadDoubleWord(long offset) 38 { 39 return RegistersCollection.Read(offset); 40 } 41 Reset()42 public override void Reset() 43 { 44 RegistersCollection.Reset(); 45 bufferAddress = 0; 46 } 47 48 public long Size => 0x100; 49 public DoubleWordRegisterCollection RegistersCollection { get; private set; } 50 Repaint()51 protected override void Repaint() 52 { 53 sysbus.ReadBytes(bufferAddress, buffer.Length, buffer, 0); 54 } 55 DefineRegisters()56 private void DefineRegisters() 57 { 58 Registers.DriverClockingMMCMDrdy.Define(this) 59 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true) // this should always be ready 60 ; 61 62 Registers.InitiatorHres.DefineMany(this, 2, stepInBytes: 4, setup: (reg, idx) => 63 reg.WithValueField(0, 8, out hres[idx], name: $"h_res_{idx}").WithIgnoredBits(8, 24)) // ignore upper bits to avoid unnecessary warnings in log 64 ; 65 66 Registers.InitiatorVres.DefineMany(this, 2, stepInBytes: 4, setup: (reg, idx) => 67 reg.WithValueField(0, 8, out vres[idx], name: $"v_res_{idx}").WithIgnoredBits(8, 24)) // ignore upper bits to avoid unnecessary warnings in log 68 ; 69 70 Registers.InitiatorBase.DefineMany(this, 4, stepInBytes: 4, setup: (reg, idx) => 71 reg.WithValueField(0, 8, out bufferRegisters[idx], name: $"base_{idx}").WithIgnoredBits(8, 24)) // ignore upper bits to avoid unnecessary warnings in log 72 ; 73 74 Registers.InitiatorEnable.Define(this) 75 .WithFlag(0, writeCallback: (_, val) => 76 { 77 if(val) 78 { 79 var height = (int)((vres[0].Value << 8) | vres[1].Value); 80 var width = (int)((hres[0].Value << 8) | hres[1].Value); 81 bufferAddress = (uint)((bufferRegisters[0].Value << 24) | (bufferRegisters[1].Value << 16) | (bufferRegisters[2].Value << 8) | bufferRegisters[3].Value); 82 83 var memoryBase = (uint)sysbus.GetRegistrationPoints(memory).First().Range.StartAddress; 84 bufferAddress += memoryBase; 85 86 this.Log(LogLevel.Debug, "Reconfiguring screen to {0}x{1}", width, height); 87 88 Reconfigure(width, height, format); 89 } 90 else 91 { 92 // it stops the repainter by passing nulls 93 Reconfigure(); 94 } 95 }) 96 ; 97 } 98 99 private IValueRegisterField[] vres = new IValueRegisterField[2]; 100 private IValueRegisterField[] hres = new IValueRegisterField[2]; 101 private IValueRegisterField[] bufferRegisters = new IValueRegisterField[4]; 102 103 private uint bufferAddress; 104 105 private readonly IBusPeripheral memory; 106 private readonly IBusController sysbus; 107 private readonly PixelFormat format; 108 109 private enum Registers 110 { 111 UnderflowEnable = 0x0, 112 UnderflowUpdate = 0x4, 113 UnderflowCounter = 0x8, 114 115 InitiatorEnable = 0x18, 116 InitiatorHres = 0x1c, 117 InitiatorHsyncStart = 0x24, 118 InitiatorHsyncEnd = 0x2c, 119 InitiatorHscan = 0x34, 120 InitiatorVres = 0x3c, 121 InitiatorVsyncStart = 0x44, 122 InitiatorVsyncEnd = 0x4c, 123 InitatorVscan = 0x54, 124 InitiatorBase = 0x5c, 125 InitiatorLenght = 0x6c, 126 127 DmaDelay = 0x7c, 128 129 DriverClockingMMCMReset = 0x8c, 130 DriverClockingMMCMRead = 0x90, 131 DriverClockingMMCMWrite = 0x94, 132 DriverClockingMMCMDrdy = 0x98, 133 DriverClockingMMCMAdr = 0x9c, 134 DriverClockingMMCMDatW = 0xa0, 135 DriverClockingMMCMDatR = 0xa8 136 } 137 } 138 } 139