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.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Peripherals.Bus;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.GPIOPort
15 {
16     public class Renesas_GPIO : BaseGPIOPort, IBytePeripheral, IWordPeripheral, IKnownSize
17     {
Renesas_GPIO(Machine machine)18         public Renesas_GPIO(Machine machine) : base(machine, NumberOfPorts * NumberOfPinsPerPort)
19         {
20             portMode = new IEnumRegisterField<Mode>[NumberOfPorts][];
21 
22             DefineRegisters();
23         }
24 
ReadByte(long offset)25         public byte ReadByte(long offset)
26         {
27             return byteRegisters.Read(offset);
28         }
29 
WriteByte(long offset, byte value)30         public void WriteByte(long offset, byte value)
31         {
32             byteRegisters.Write(offset, value);
33         }
34 
ReadWord(long offset)35         public ushort ReadWord(long offset)
36         {
37             return wordRegisters.Read(offset);
38         }
39 
WriteWord(long offset, ushort value)40         public void WriteWord(long offset, ushort value)
41         {
42             wordRegisters.Write(offset, value);
43         }
44 
Reset()45         public override void Reset()
46         {
47             base.Reset();
48             byteRegisters.Reset();
49             wordRegisters.Reset();
50         }
51 
52         public long Size => 0x10000;
53 
DefineRegisters()54         private void DefineRegisters()
55         {
56             var byteRegistersMap = new Dictionary <long, ByteRegister>();
57             var wordRegistersMap = new Dictionary <long, WordRegister>();
58 
59             for(int i = 0; i < NumberOfPorts; i++)
60             {
61                 byteRegistersMap[(long)Registers.Port + i] = new ByteRegister(this)
62                     .WithEnumFields<ByteRegister, byte>(0, 1, NumberOfPinsPerPort, name: "Pm",
63                         valueProviderCallback: CreatePortRegisterValueProviderCallback(i),
64                         writeCallback: CreatePortRegisterWriteCallback(i)
65                     );
66 
67                 // these registers are necessary to allow software read back the previously written value
68                 byteRegistersMap[(long)Registers.PortModeControl + i] = new ByteRegister(this)
69                     .WithEnumFields<ByteRegister, byte>(0, 1, NumberOfPinsPerPort, name: "PMCm");
70                 byteRegistersMap[(long)Registers.PortRegionSelect + i] = new ByteRegister(this)
71                     .WithEnumFields<ByteRegister, byte>(0, 1, NumberOfPinsPerPort, name: "RSELPm");
72 
73                 wordRegistersMap[(long)Registers.PortMode + 0x2 * i] = new WordRegister(this)
74                     .WithEnumFields<WordRegister, Mode>(0, 2, NumberOfPinsPerPort, out portMode[i], name: "PMm",
75                         writeCallback: CreatePortModeRegisterWriteCallback(i)
76                     );
77             }
78 
79             byteRegisters = new ByteRegisterCollection(this, byteRegistersMap);
80             wordRegisters = new WordRegisterCollection(this, wordRegistersMap);
81         }
82 
CreatePortRegisterValueProviderCallback(int port)83         private Func<int, byte, byte> CreatePortRegisterValueProviderCallback(int port)
84         {
85             return (idx, _) => Connections[port * NumberOfPinsPerPort + idx].IsSet ? (byte)1 : (byte)0;
86         }
87 
CreatePortRegisterWriteCallback(int port)88         private Action<int, byte, byte> CreatePortRegisterWriteCallback(int port)
89         {
90             return (idx, _, value) => Connections[port * NumberOfPinsPerPort + idx].Set(value == (byte)1);
91         }
92 
CreatePortModeRegisterWriteCallback(int port)93         private Action<int, Mode, Mode> CreatePortModeRegisterWriteCallback(int port)
94         {
95             return (idx, oldValue, newValue) =>
96             {
97                 if(newValue != Mode.Output)
98                 {
99                     this.Log(LogLevel.Warning, "{0:X} - port mode not supported, keeping the previous value: {0:X}", oldValue);
100                     portMode[port][idx].Value = oldValue;
101                 }
102             };
103         }
104 
105         private const int NumberOfPorts = 25;
106         private const int NumberOfPinsPerPort = 8;
107 
108         private readonly IEnumRegisterField<Mode>[][] portMode;
109 
110         private ByteRegisterCollection byteRegisters;
111         private WordRegisterCollection wordRegisters;
112 
113         private enum Mode
114         {
115             HiZ = 0x0,
116             Input = 0x1,
117             Output = 0x2,
118             OutputInputBuffer = 0x3,
119         }
120 
121         private enum Registers
122         {
123             Port = 0x0,
124             PortMode = 0x200,
125             PortModeControl = 0x400,
126             PortRegionSelect = 0xc00,
127         }
128     }
129 }
130