1 // 2 // Copyright (c) 2010-2024 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 Antmicro.Renode.Core; 9 using Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Utilities; 12 13 namespace Antmicro.Renode.Peripherals.GPIOPort 14 { 15 public class RenesasDA14_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 16 { RenesasDA14_GPIO(IMachine machine)17 public RenesasDA14_GPIO(IMachine machine) : base(machine, NumberOfPorts * PinsPerPort) 18 { 19 RegistersCollection = new DoubleWordRegisterCollection(this); 20 21 ports = new Port[NumberOfPorts]; 22 for(var portNumber = 0; portNumber < ports.Length; ++portNumber) 23 { 24 ports[portNumber] = new Port(portNumber, this); 25 } 26 27 DefineCommonRegisters(); 28 29 Reset(); 30 } 31 ReadDoubleWord(long offset)32 public uint ReadDoubleWord(long offset) 33 { 34 return RegistersCollection.Read(offset); 35 } 36 WriteDoubleWord(long offset, uint value)37 public void WriteDoubleWord(long offset, uint value) 38 { 39 RegistersCollection.Write(offset, value); 40 } 41 Reset()42 public override void Reset() 43 { 44 base.Reset(); 45 RegistersCollection.Reset(); 46 } 47 DefineCommonRegisters()48 private void DefineCommonRegisters() 49 { 50 Registers.ClockSel.Define(this) 51 .WithTag("FUNC_CLOCK_SEL", 0, 3) 52 .WithTaggedFlag("FUNC_CLOCK_EN", 3) 53 .WithReservedBits(4, 3) 54 .WithTaggedFlag("XTAL32M_OUTPUT_EN", 8) 55 .WithTaggedFlag("RC32M_OUTPUT_EN", 9) 56 .WithTaggedFlag("DIVN_OUTPUT_EN", 10); 57 } 58 59 public DoubleWordRegisterCollection RegistersCollection { get; } 60 61 public long Size => 0x200; 62 63 private readonly Port[] ports; 64 65 private const int NumberOfPorts = 2; 66 private const int PinsPerPort = 16; 67 68 private class Port 69 { Port(int portNumber, RenesasDA14_GPIO parent)70 public Port(int portNumber, RenesasDA14_GPIO parent) 71 { 72 this.portNumber = portNumber; 73 this.parent = parent; 74 75 parent.RegistersCollection.DefineRegister((long)Registers.DataPort0 + (4 * portNumber), 0x142) 76 .WithValueField(0, 16, name: $"P{portNumber}_DATA", 77 valueProviderCallback: _ => GetStateValue(), 78 writeCallback: (_, value) => SetStateValue(value)); 79 parent.RegistersCollection.DefineRegister((long)Registers.SetDataPort0 + (4 * portNumber)) 80 .WithValueField(0, 16, name: $"P{portNumber}_SET", 81 valueProviderCallback: _ => 0, 82 writeCallback: (_, value) => SetStateValue(GetStateValue() | value)); 83 parent.RegistersCollection.DefineRegister((long)Registers.ResetDataPort0 + (4 * portNumber)) 84 .WithValueField(0, 16, name: $"P{portNumber}_RESET", 85 valueProviderCallback: _ => 0, 86 writeCallback: (_, value) => SetStateValue(GetStateValue() | ~value)); 87 parent.RegistersCollection.DefineRegister((long)Registers.WeakControlPort0 + (4 * portNumber)) 88 .WithValueField(0, 16, out strength, name: $"P{portNumber}_LOWDRV"); 89 90 direction = new IEnumRegisterField<Directions>[PinsPerPort]; 91 92 for(var pin = 0; pin < PinsPerPort; ++pin) 93 { 94 parent.RegistersCollection.DefineRegister((long)Registers.ModePort0Pin00 + (4 * pin) + (4 * PinsPerPort * portNumber), 0x200) 95 .WithTag("PID", 0, 6) // pin function 96 .WithReservedBits(6, 2) 97 .WithEnumField<DoubleWordRegister, Directions>(8, 2, out direction[pin], name: "PUPD", 98 writeCallback: (_, __) => RefreshConnectionsState()) 99 .WithTaggedFlag("PPOD", 10); 100 } 101 } 102 IsOutputPin(int pinNumber)103 private bool IsOutputPin(int pinNumber) 104 { 105 return direction[pinNumber].Value == Directions.Output; 106 } 107 GetStateValue()108 private ulong GetStateValue() 109 { 110 ulong result = 0; 111 112 for(byte bitIndex = 0; bitIndex < PinsPerPort; bitIndex++) 113 { 114 var idx = PinsPerPort * portNumber + bitIndex; 115 116 BitHelper.SetBit(ref result, bitIndex, IsOutputPin(bitIndex) 117 ? parent.Connections[idx].IsSet 118 : parent.State[idx]); 119 } 120 121 return result; 122 } 123 SetStateValue(ulong value)124 private void SetStateValue(ulong value) 125 { 126 state = value; 127 RefreshConnectionsState(); 128 } 129 RefreshConnectionsState()130 private void RefreshConnectionsState() 131 { 132 for(byte bitIndex = 0; bitIndex < PinsPerPort; bitIndex++) 133 { 134 if(IsOutputPin(bitIndex)) 135 { 136 var connection = parent.Connections[PinsPerPort * portNumber + bitIndex]; 137 var pinState = BitHelper.IsBitSet(state, bitIndex); 138 139 connection.Set(pinState); 140 } 141 } 142 } 143 144 private ulong state; 145 146 private readonly IEnumRegisterField<Directions>[] direction; 147 private readonly IValueRegisterField strength; 148 149 private readonly int portNumber; 150 private readonly RenesasDA14_GPIO parent; 151 152 private enum Directions 153 { 154 InputNoResistors = 0b00, 155 InputPullUp = 0b01, 156 InputPullDown = 0b10, 157 Output = 0b11 158 } 159 } 160 161 private enum Registers 162 { 163 DataPort0 = 0x0, 164 DataPort1 = 0x4, 165 SetDataPort0 = 0x8, 166 SetDataPort1 = 0xC, 167 ResetDataPort0 = 0x10, 168 ResetDataPort1 = 0x14, 169 170 ModePort0Pin00 = 0x18, 171 ModePort0Pin01 = 0x1C, 172 ModePort0Pin02 = 0x20, 173 ModePort0Pin03 = 0x24, 174 ModePort0Pin04 = 0x28, 175 ModePort0Pin05 = 0x2C, 176 ModePort0Pin06 = 0x30, 177 ModePort0Pin07 = 0x34, 178 ModePort0Pin08 = 0x38, 179 ModePort0Pin09 = 0x3c, 180 ModePort0Pin10 = 0x40, 181 ModePort0Pin11 = 0x44, 182 ModePort0Pin12 = 0x48, 183 ModePort0Pin13 = 0x4c, 184 ModePort0Pin14 = 0x50, 185 ModePort0Pin15 = 0x54, 186 187 ModePort1Pin00 = 0x58, 188 ModePort1Pin01 = 0x5c, 189 ModePort1Pin02 = 0x60, 190 ModePort1Pin03 = 0x64, 191 ModePort1Pin04 = 0x68, 192 ModePort1Pin05 = 0x6c, 193 ModePort1Pin06 = 0x70, 194 ModePort1Pin07 = 0x74, 195 ModePort1Pin08 = 0x78, 196 ModePort1Pin09 = 0x7c, 197 ModePort1Pin10 = 0x80, 198 ModePort1Pin11 = 0x84, 199 ModePort1Pin12 = 0x88, 200 ModePort1Pin13 = 0x8c, 201 ModePort1Pin14 = 0x90, 202 ModePort1Pin15 = 0x94, 203 204 ClockSel = 0xA0, 205 WeakControlPort0 = 0xA4, 206 WeakControlPort1 = 0xA8, 207 } 208 } 209 } 210