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