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.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.Peripherals.GPIOPort 18 { 19 public class LiteX_ControlAndStatus : BaseGPIOPort, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 20 { LiteX_ControlAndStatus(IMachine machine)21 public LiteX_ControlAndStatus(IMachine machine) : base(machine, LedsCount + SwitchesCount + ButtonsCount) 22 { 23 buttonsPending = new bool[ButtonsCount]; 24 IRQ = new GPIO(); 25 26 RegistersCollection = new DoubleWordRegisterCollection(this); 27 DefineRegisters(); 28 } 29 ReadDoubleWord(long offset)30 public uint ReadDoubleWord(long offset) 31 { 32 return RegistersCollection.Read(offset); 33 } 34 WriteDoubleWord(long offset, uint value)35 public void WriteDoubleWord(long offset, uint value) 36 { 37 RegistersCollection.Write(offset, value); 38 } 39 Reset()40 public override void Reset() 41 { 42 base.Reset(); 43 RegistersCollection.Reset(); 44 Array.Clear(buttonsPending, 0, buttonsPending.Length); 45 46 UpdateInterrupt(); 47 } 48 OnGPIO(int number, bool value)49 public override void OnGPIO(int number, bool value) 50 { 51 if(number >= 0 && number < LedsCount) 52 { 53 this.Log(LogLevel.Warning, "Input not allowed on LED ports"); 54 return; 55 } 56 57 base.OnGPIO(number, value); 58 59 // here we are interested only in buttons as their state is latached and generates interrupt 60 if(number >= LedsCount + SwitchesCount) 61 { 62 var buttonId = number - (LedsCount + SwitchesCount); 63 buttonsPending[buttonId] |= value; 64 65 UpdateInterrupt(); 66 } 67 } 68 69 public GPIO IRQ { get; } 70 71 public long Size => 0x14; 72 73 public DoubleWordRegisterCollection RegistersCollection { get; } 74 DefineRegisters()75 private void DefineRegisters() 76 { 77 // according to LiteX-generated `csr.h` this register is readable 78 Registers.Leds.Define(this) 79 .WithValueField(0, LedsCount, 80 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(Connections.Where(x => x.Key >= 0).OrderBy(x => x.Key).Select(x => x.Value.IsSet)), 81 writeCallback: (_, val) => 82 { 83 var bits = BitHelper.GetBits((uint)val); 84 for(var i = 0; i < LedsCount; i++) 85 { 86 Connections[i].Set(bits[i]); 87 } 88 }) 89 ; 90 91 Registers.Switches.Define(this) 92 .WithValueField(0, SwitchesCount, FieldMode.Read, 93 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(this.State.Skip(LedsCount).Take(SwitchesCount))) 94 ; 95 96 Registers.ButtonsStatus.Define(this) 97 .WithValueField(0, ButtonsCount, FieldMode.Read, 98 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(this.State.Skip(LedsCount + SwitchesCount).Take(ButtonsCount))) 99 ; 100 101 Registers.ButtonsPending.Define(this) 102 .WithValueField(0, ButtonsCount, 103 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(buttonsPending), 104 writeCallback: (_, val) => 105 { 106 foreach(var bit in BitHelper.GetSetBits(val)) 107 { 108 buttonsPending[bit] = false; 109 } 110 111 UpdateInterrupt(); 112 }) 113 ; 114 115 Registers.ButtonsEnabled.Define(this) 116 .WithValueField(0, ButtonsCount, out buttonsEnabled, writeCallback: (_, __) => { UpdateInterrupt(); }) 117 ; 118 } 119 UpdateInterrupt()120 private void UpdateInterrupt() 121 { 122 var enabled = BitHelper.GetBits((uint)buttonsEnabled.Value).Take(ButtonsCount); 123 IRQ.Set(enabled.Zip(buttonsPending, (en, pe) => en && pe).Any()); 124 } 125 126 private IValueRegisterField buttonsEnabled; 127 128 private readonly bool[] buttonsPending; 129 130 private const int LedsCount = 32; 131 private const int SwitchesCount = 32; 132 private const int ButtonsCount = 32; 133 134 private enum Registers 135 { 136 Leds = 0x0, 137 Switches = 0x4, 138 ButtonsStatus = 0x8, 139 ButtonsPending = 0xC, 140 ButtonsEnabled = 0x10, 141 } 142 } 143 } 144