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 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.GPIOPort 17 { 18 [AllowedTranslations(AllowedTranslation.WordToDoubleWord)] 19 public class STM32F1GPIOPort : BaseGPIOPort, IDoubleWordPeripheral 20 { STM32F1GPIOPort(IMachine machine)21 public STM32F1GPIOPort(IMachine machine) : base(machine, NumberOfPorts) 22 { 23 pins = new PinMode[NumberOfPorts]; 24 25 var configurationLowRegister = new DoubleWordRegister(this, 0x44444444); 26 var configurationHighRegister = new DoubleWordRegister(this, 0x44444444); 27 for(var offset = 0; offset < 32; offset += 4) 28 { 29 var lowId = offset / 4; 30 var highId = lowId + 8; 31 32 configurationLowRegister.DefineEnumField<PinMode>(offset, 2, name: $"MODE{lowId}", writeCallback: (_, value) => pins[lowId] = value, valueProviderCallback: _ => pins[lowId]); 33 configurationLowRegister.Tag($"CNF{lowId}", offset + 2, 2); 34 35 configurationHighRegister.DefineEnumField<PinMode>(offset, 2, name: $"MODE{highId}", writeCallback: (_, value) => pins[highId] = value, valueProviderCallback: _ => pins[highId]); 36 configurationHighRegister.Tag($"CNF{highId}", offset + 2, 2); 37 } 38 39 var registersMap = new Dictionary<long, DoubleWordRegister> 40 { 41 {(long)Registers.ConfigurationLow, configurationLowRegister}, 42 43 {(long)Registers.ConfigurationHigh, configurationHighRegister}, 44 45 {(long)Registers.InputData, new DoubleWordRegister(this) 46 // upper 16 bits are reserved 47 .WithValueField(0, 16, FieldMode.Read, name: "IDR", valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(State)) 48 }, 49 50 {(long)Registers.OutputData, new DoubleWordRegister(this) 51 // upper 16 bits are reserved 52 .WithValueField(0, 16, name: "ODR", writeCallback: (_, value) => SetConnectionsStateUsingBits((uint)value), valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(Connections.Values.Select(x=>x.IsSet))) 53 }, 54 55 {(long)Registers.BitSetReset, new DoubleWordRegister(this) 56 .WithValueField(16, 16, FieldMode.Write, name: "BR", writeCallback: (_, value) => SetBitsFromMask((uint)value, false)) 57 .WithValueField(0, 16, FieldMode.Write, name: "BS", writeCallback: (_, value) => SetBitsFromMask((uint)value, true)) 58 }, 59 60 {(long)Registers.BitReset, new DoubleWordRegister(this) 61 // upper 16 bits are reserved 62 .WithValueField(0, 16, FieldMode.Write, name: "BR", writeCallback: (_, value) => SetBitsFromMask((uint)value, false)) 63 } 64 }; 65 66 registers = new DoubleWordRegisterCollection(this, registersMap); 67 68 Reset(); 69 } 70 ReadDoubleWord(long offset)71 public uint ReadDoubleWord(long offset) 72 { 73 return registers.Read(offset); 74 } 75 WriteDoubleWord(long offset, uint value)76 public void WriteDoubleWord(long offset, uint value) 77 { 78 registers.Write(offset, value); 79 } 80 OnGPIO(int number, bool value)81 public override void OnGPIO(int number, bool value) 82 { 83 if(!CheckPinNumber(number)) 84 { 85 return; 86 } 87 88 if(pins[number] != PinMode.Input) 89 { 90 this.Log(LogLevel.Warning, "Received a signal on the output pin #{0}", number); 91 return; 92 } 93 94 base.OnGPIO(number, value); 95 Connections[number].Set(value); 96 } 97 Reset()98 public override void Reset() 99 { 100 base.Reset(); 101 registers.Reset(); 102 } 103 SetBitsFromMask(uint mask, bool state)104 private void SetBitsFromMask(uint mask, bool state) 105 { 106 foreach(var bit in BitHelper.GetSetBits(mask)) 107 { 108 if(pins[bit] == PinMode.Input) 109 { 110 this.Log(LogLevel.Warning, "Trying to set the state of the input pin #{0}", bit); 111 continue; 112 } 113 114 Connections[bit].Set(state); 115 State[bit] = state; 116 } 117 } 118 119 private readonly DoubleWordRegisterCollection registers; 120 private readonly PinMode[] pins; 121 122 private enum Registers 123 { 124 ConfigurationLow = 0x00, 125 ConfigurationHigh = 0x04, 126 InputData = 0x08, 127 OutputData = 0x0C, 128 BitSetReset = 0x10, 129 BitReset = 0x14, 130 PortConfigurationLock = 0x18 131 } 132 133 private enum PinMode 134 { 135 Input = 0, 136 Output10Mhz = 1, 137 Output2Mhz = 2, 138 Output50Mhz = 3 139 } 140 141 private const int NumberOfPorts = 16; 142 } 143 } 144