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