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 System.Collections.Generic;
9 using System.Collections.ObjectModel;
10 using System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Peripherals.Bus;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     public class RenesasRZG_MHU : IDoubleWordPeripheral, INumberedGPIOOutput, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
18     {
RenesasRZG_MHU()19         public RenesasRZG_MHU()
20         {
21             messageInterruptsNonSecure = new GPIO[ChannelCount];
22             responseInterruptsNonSecure = new GPIO[ChannelCount];
23             messageInterruptsSecure = new GPIO[ChannelCount];
24             responseInterruptsSecure = new GPIO[ChannelCount];
25 
26             RegistersCollection = new DoubleWordRegisterCollection(this, BuildRegisterMap());
27             Connections = new ReadOnlyDictionary<int, IGPIO>(
28                 messageInterruptsSecure
29                     .Concat(responseInterruptsSecure)
30                     .Concat(messageInterruptsNonSecure)
31                     .Concat(responseInterruptsNonSecure)
32                     .Select((x, i) => new { Key = i, Value = (IGPIO)x })
33                     .ToDictionary(x => x.Key, x => x.Value)
34             );
35         }
36 
Reset()37         public void Reset()
38         {
39             RegistersCollection.Reset();
40             foreach(var conn in Connections)
41             {
42                 conn.Value.Unset();
43             }
44             foreach(var irq in softwareInterrupts)
45             {
46                 irq.Unset();
47             }
48         }
49 
ReadDoubleWord(long offset)50         public uint ReadDoubleWord(long offset)
51         {
52             return RegistersCollection.Read(offset);
53         }
54 
WriteDoubleWord(long offset, uint value)55         public void WriteDoubleWord(long offset, uint value)
56         {
57             RegistersCollection.Write(offset, value);
58         }
59 
60         public long Size => 0x1800;
61         public DoubleWordRegisterCollection RegistersCollection { get; }
62         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
63         public GPIO SoftwareIRQ0 => softwareInterrupts[0];
64         public GPIO SoftwareIRQ1 => softwareInterrupts[1];
65         public GPIO SoftwareIRQ2 => softwareInterrupts[2];
66         public GPIO SoftwareIRQ3 => softwareInterrupts[3];
67 
BuildRegisterMap()68         private Dictionary<long, DoubleWordRegister> BuildRegisterMap()
69         {
70             var registerMap = BuildChannelRegisterMap(0x0, false)
71                 .Concat(BuildChannelRegisterMap(0x1000, true))
72                 .ToDictionary(x => x.Key, x => x.Value);
73 
74             for(long i = 0; i < softwareInterrupts.Length; ++i)
75             {
76                 long offset = 0x10 * i;
77                 BuildInterruptRegisters(registerMap, softwareInterrupts[i], offset + (long)Registers.SoftwareInterruptStatus);
78             }
79 
80             return registerMap;
81         }
82 
BuildChannelRegisterMap(long baseOffset, bool secure)83         private Dictionary<long, DoubleWordRegister> BuildChannelRegisterMap(long baseOffset, bool secure)
84         {
85             var registerMap = new Dictionary<long, DoubleWordRegister>();
86 
87             var messageIrqs = secure ? messageInterruptsSecure : messageInterruptsNonSecure;
88             var responseIrqs = secure ? responseInterruptsSecure : responseInterruptsNonSecure;
89 
90             for(long i = 0; i < ChannelCount; ++i)
91             {
92                 long offset = baseOffset + 0x20 * i;
93                 var msgIrq = new GPIO();
94                 var rspIrq = new GPIO();
95 
96                 BuildInterruptRegisters(registerMap, msgIrq, offset + (long)Registers.MessageInterruptStatus);
97                 BuildInterruptRegisters(registerMap, rspIrq, offset + (long)Registers.ResponseInterruptStatus);
98 
99                 messageIrqs[i] = msgIrq;
100                 responseIrqs[i] = rspIrq;
101             }
102 
103             return registerMap;
104         }
105 
BuildInterruptRegisters(Dictionary<long, DoubleWordRegister> registerMap, GPIO irq, long baseOffset)106         private void BuildInterruptRegisters(Dictionary<long, DoubleWordRegister> registerMap, GPIO irq, long baseOffset)
107         {
108             registerMap.Add(baseOffset + 0x0, new DoubleWordRegister(this)
109                 .WithFlag(0, FieldMode.Read, name: "STAT",
110                     valueProviderCallback: _ => irq.IsSet
111                 )
112                 .WithReservedBits(1, 31)
113             );
114             registerMap.Add(baseOffset + 0x4, new DoubleWordRegister(this)
115                 .WithFlag(0, FieldMode.Write, name: "SET",
116                     writeCallback: (_, value) =>
117                     {
118                         if(value)
119                         {
120                             irq.Set();
121                         }
122                     }
123                 )
124                 .WithReservedBits(1, 31)
125             );
126             registerMap.Add(baseOffset + 0x8, new DoubleWordRegister(this)
127                 .WithFlag(0, FieldMode.Write, name: "CLEAR",
128                     writeCallback: (_, value) =>
129                     {
130                         if(value)
131                         {
132                             irq.Unset();
133                         }
134                     }
135                 )
136                 .WithReservedBits(1, 31)
137             );
138         }
139 
140         private readonly GPIO[] softwareInterrupts = {new GPIO(), new GPIO(), new GPIO(), new GPIO()};
141         private readonly GPIO[] messageInterruptsNonSecure;
142         private readonly GPIO[] responseInterruptsNonSecure;
143         private readonly GPIO[] messageInterruptsSecure;
144         private readonly GPIO[] responseInterruptsSecure;
145 
146         private const long ChannelCount = 6;
147 
148         public enum Registers : long
149         {
150             MessageInterruptStatus  = 0x000, // MSG_INT_STSn
151             MessageInterruptSet     = 0x004, // MSG_INT_SETn
152             MessageInterruptClear   = 0x008, // MSG_INT_CLRn
153             ResponseInterruptStatus = 0x010, // RSP_INT_STSn
154             ResponseInterruptSet    = 0x014, // RSP_INT_SETn
155             ResponseInterruptClear  = 0x018, // RSP_INT_CLRn
156             SoftwareInterruptStatus = 0x800, // SW_INT_STSn
157             SoftwareInterruptSet    = 0x804, // SW_INT_SETn
158             SoftwareInterruptClear  = 0x808, // SW_INT_CLRn
159         }
160     }
161 }
162