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 
8 using System.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Exceptions;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.I2C;
17 
18 namespace Antmicro.Renode.Peripherals.Miscellaneous
19 {
20     public class EOSS3_FlexibleFusionEngine : BasicDoubleWordPeripheral, IKnownSize, IPeripheralContainer<IBytePeripheral, NumberRegistrationPoint<int>>
21     {
EOSS3_FlexibleFusionEngine(IMachine machine)22         public EOSS3_FlexibleFusionEngine(IMachine machine) : base(machine)
23         {
24             children = new Dictionary<int, IBytePeripheral>();
25             DefineRegisters();
26         }
27 
Reset()28         public override void Reset()
29         {
30             base.Reset();
31             foreach(var child in children.Values)
32             {
33                 child.Reset();
34             }
35         }
36 
GetRegistrationPoints(IBytePeripheral peripheral)37         public IEnumerable<NumberRegistrationPoint<int>> GetRegistrationPoints(IBytePeripheral peripheral)
38         {
39             return children.Keys.Select(x => new NumberRegistrationPoint<int>(x));
40         }
41 
42         public IEnumerable<IRegistered<IBytePeripheral, NumberRegistrationPoint<int>>> Children
43         {
44             get
45             {
46                 return children.Select(x => Registered.Create(x.Value, new NumberRegistrationPoint<int>(x.Key)));
47             }
48         }
49 
Register(IBytePeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)50         public virtual void Register(IBytePeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)
51         {
52             if(children.ContainsKey(registrationPoint.Address))
53             {
54                 throw new RegistrationException("The specified registration point is already in use.");
55             }
56             if(!(peripheral is OpenCoresI2C))
57             {
58                 throw new RegistrationException("The FFE Wishbone interface supports the OpenCoresI2C controller only");
59             }
60             children.Add(registrationPoint.Address, peripheral);
61             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
62         }
63 
Unregister(IBytePeripheral peripheral)64         public virtual void Unregister(IBytePeripheral peripheral)
65         {
66             var toRemove = children.Where(x => x.Value.Equals(peripheral)).Select(x => x.Key).ToList();
67             if(toRemove.Count == 0)
68             {
69                 throw new RegistrationException("The specified peripheral was never registered.");
70             }
71             foreach(var key in toRemove)
72             {
73                 children.Remove(key);
74             }
75             machine.UnregisterAsAChildOf(this, peripheral);
76         }
77 
78         public long Size => 0x2000;
79 
DefineRegisters()80         private void DefineRegisters()
81         {
82             Registers.WishboneAddress.Define(this)
83                 .WithValueField(0, 3, out slaveAddress, name: "Addr")
84                 .WithReservedBits(3, 3)
85                 .WithEnumField(6, 2, out selectedSlave, name: "slave_sel")
86                 .WithReservedBits(8, 24)
87             ;
88 
89             Registers.WriteData.Define(this)
90                 .WithValueField(0, 8, out writeData, name: "WDATA")
91                 .WithReservedBits(8, 24)
92             ;
93 
94             Registers.ControlAndStatus.Define(this)
95                 .WithFlag(0, out startTransfer, FieldMode.Set, name: "wb_ms_start")
96                 .WithFlag(1, out isWrite, name: "wb_ms_wen")
97                 .WithTaggedFlag("mux_wb_sn", 2)
98                 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => false, name: "BUSY")
99                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "OVFL")
100                 // These are three fields defining if the peripheral should be controlled from wishbone bus master or Sensor Manager.
101                 // We assume the selectedSlave is configured anyway.
102                 .WithValueField(5, 3, name: "mux_sel")
103                 .WithReservedBits(8, 24)
104                 .WithWriteCallback(ControlWrite)
105             ;
106 
107             Registers.ReadData.Define(this)
108                 .WithValueField(0, 8, out readData, FieldMode.Read, name: "RDATA")
109                 .WithReservedBits(8, 24)
110             ;
111         }
112 
ControlWrite(uint _, uint value)113         private void ControlWrite(uint _, uint value)
114         {
115             if(!children.TryGetValue((int)selectedSlave.Value, out var slave))
116             {
117                 this.Log(LogLevel.Warning, "Trying to {1} slave {0}, but it is not registered", selectedSlave.Value,
118                     isWrite.Value ? "write to" : "read from");
119                 return;
120             }
121             if(startTransfer.Value)
122             {
123                 startTransfer.Value = false;
124                 if(isWrite.Value)
125                 {
126                     this.Log(LogLevel.Noisy, "Writing to slave {0} at 0x{1:X}, value 0x{2:X}", selectedSlave.Value, slaveAddress.Value, writeData.Value);
127                     slave.WriteByte((long)slaveAddress.Value << 2, (byte)writeData.Value);
128                 }
129                 else
130                 {
131                     readData.Value = slave.ReadByte((long)slaveAddress.Value << 2);
132                     this.Log(LogLevel.Noisy, "Read from slave {0} at 0x{1:X}, value 0x{2:X}", selectedSlave.Value, slaveAddress.Value, readData.Value);
133                 }
134             }
135         }
136 
137         private Dictionary<int, IBytePeripheral> children;
138         private IFlagRegisterField isWrite;
139         private IValueRegisterField slaveAddress;
140         private IFlagRegisterField startTransfer;
141         private IValueRegisterField writeData;
142         private IValueRegisterField readData;
143         private IEnumRegisterField<WishboneSlave> selectedSlave;
144 
145         private enum WishboneSlave
146         {
147             I2CMaster0 = 0,
148             I2CMaster1 = 1,
149             SPIMaster0 = 2
150         }
151 
152         private enum Registers
153         {
154             WishboneAddress = 0x0,
155             WriteData = 0x4,
156             ControlAndStatus = 0x8,
157             ReadData= 0xC,
158             SRAMTest1 = 0x14,
159             SRAMTest2 = 0x18,
160             FFEControlAndStatus = 0x20,
161             FFEDebugCombined = 0x38,
162             Command = 0x100,
163             Interrupt = 0x108,
164             InterruptEnable = 0x10c,
165             Status = 0x110,
166             MailboxToFFE0 = 0x114,
167             SMRuntimeAddress = 0x120,
168             SM0RuntimeAddressControl = 0x124,
169             SM1RuntimeAddressControl = 0x128,
170             SM0RuntimeAddressCurrent = 0x12c,
171             SM1RuntimeAddressCurrent = 0x130,
172             SM0DebugSelection = 0x140,
173             SM1DebugSelection = 0x144,
174             FFEDebugSelection = 0x148,
175             FFE0BreakpointConfig = 0x150,
176             FFE0BreakPointContinue = 0x154,
177             FFE0BreakPointStatus = 0x158,
178             FFE0BreakpointProgramCounter0 = 0x160,
179             FFE0BreakpointProgramCounter1 = 0x164,
180             FFE0BreakpointProgramCounter2 = 0x168,
181             FFE0BreakpointProgramCounter3 = 0x16c,
182         }
183     }
184 }
185