1 // 2 // Copyright (c) 2010-2019 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.IO; 9 using System.Net.Sockets; 10 using System.Runtime.InteropServices; 11 using Antmicro.Renode.Exceptions; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals 17 { 18 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 19 public class EtherBoneBridge : IDoubleWordPeripheral, IDisposable, IAbsoluteAddressAware 20 { EtherBoneBridge(int port, string host = R)21 public EtherBoneBridge(int port, string host = "127.0.0.1") 22 { 23 try 24 { 25 connection = new TcpClient(host, port); 26 dataStream = connection.GetStream(); 27 } 28 catch(SocketException) 29 { 30 throw new ConstructionException(string.Format("Could not connect to EtherBone server at {0}:{1}", host, port)); 31 } 32 33 ebRecord.Magic = 0x4e6f; // this is a constant 34 ebRecord.VersionAndFlags = 0x10; // version: 1, all other flags: 0 35 ebRecord.AddressAndPortWidth = 0x44; // address width: 32 bits, port width: 32 bits 36 37 ebRecord.WishboneFlags = 0x0; // no wishbone flags 38 ebRecord.ByteEnable = 0xf; // enable all 4 bytes 39 } 40 Reset()41 public void Reset() 42 { 43 // intentionally do nothing 44 } 45 Dispose()46 public void Dispose() 47 { 48 dataStream.Close(); 49 connection.Close(); 50 } 51 SetAbsoluteAddress(ulong address)52 public void SetAbsoluteAddress(ulong address) 53 { 54 absoluteAddress = address; 55 } 56 ReadDoubleWord(long offset)57 public uint ReadDoubleWord(long offset) 58 { 59 if(!TryRead((uint)absoluteAddress, out var result)) 60 { 61 this.Log(LogLevel.Warning, "Could not read from offset 0x{0:X}. Check your connection with EtherBone server", offset); 62 } 63 64 return result; 65 } 66 WriteDoubleWord(long offset, uint val)67 public void WriteDoubleWord(long offset, uint val) 68 { 69 if(!TryWrite((uint)absoluteAddress, val)) 70 { 71 this.Log(LogLevel.Warning, "Could not write value 0x{0:X} to offset 0x{1:X}. Check your connection with EtherBone server", val, offset); 72 } 73 } 74 TryRead(uint offset, out uint result)75 private bool TryRead(uint offset, out uint result) 76 { 77 ebRecord.WritesCount = 0; 78 ebRecord.ReadsCount = 1; 79 80 ebRecord.WriteValueReadAddress = offset; 81 82 var bytes = EtherBoneRecordToBytes(ebRecord); 83 84 try 85 { 86 dataStream.Write(bytes, 0, bytes.Length); 87 } 88 catch(IOException) 89 { 90 result = 0; 91 return false; 92 } 93 94 var replyBytes = new byte[RecordSize]; 95 if(dataStream.Read(replyBytes, 0, replyBytes.Length) != RecordSize) 96 { 97 result = 0; 98 return false; 99 } 100 101 var reply = EtherBoneRecordFromBytes(replyBytes); 102 result = reply.ReadValueWriteAddress; 103 return true; 104 } 105 TryWrite(uint offset, uint val)106 private bool TryWrite(uint offset, uint val) 107 { 108 ebRecord.WritesCount = 1; 109 ebRecord.ReadsCount = 0; 110 111 ebRecord.ReadValueWriteAddress = offset; 112 ebRecord.WriteValueReadAddress = val; 113 114 var bytes = EtherBoneRecordToBytes(ebRecord); 115 116 try 117 { 118 dataStream.Write(bytes, 0, bytes.Length); 119 return true; 120 } 121 catch(IOException) 122 { 123 return false; 124 } 125 } 126 EtherBoneRecordToBytes(EtherBoneRecord ebRecord)127 private byte[] EtherBoneRecordToBytes(EtherBoneRecord ebRecord) 128 { 129 var size = Marshal.SizeOf(ebRecord); 130 var result = new byte[size]; 131 132 var ptr = Marshal.AllocHGlobal(size); 133 Marshal.StructureToPtr(ebRecord, ptr, true); 134 Marshal.Copy(ptr, result, 0, size); 135 Marshal.FreeHGlobal(ptr); 136 137 FixFieldEndianess(result); 138 139 return result; 140 } 141 EtherBoneRecordFromBytes(byte[] bytes)142 private EtherBoneRecord EtherBoneRecordFromBytes(byte[] bytes) 143 { 144 FixFieldEndianess(bytes); 145 146 var size = Marshal.SizeOf(typeof(EtherBoneRecord)); 147 var ptr = Marshal.AllocHGlobal(size); 148 149 Marshal.Copy(bytes, 0, ptr, size); 150 151 var result = (EtherBoneRecord)Marshal.PtrToStructure(ptr, typeof(EtherBoneRecord)); 152 Marshal.FreeHGlobal(ptr); 153 154 return result; 155 } 156 157 // .NET built-in struct packaging mechanism 158 // does not allow to define field's endianess, 159 // so we have to swap bytes of some fields FixFieldEndianess(byte[] arr)160 private void FixFieldEndianess(byte[] arr) 161 { 162 // swap Magic 163 Misc.SwapElements(arr, 0, 1); 164 165 // swap ReadValueWriteAddress 166 Misc.SwapElements(arr, 12, 15); 167 Misc.SwapElements(arr, 13, 14); 168 169 // swap WriteValueReadAddress 170 Misc.SwapElements(arr, 16, 19); 171 Misc.SwapElements(arr, 17, 18); 172 } 173 174 private ulong absoluteAddress; 175 private EtherBoneRecord ebRecord; 176 177 private readonly NetworkStream dataStream; 178 private readonly TcpClient connection; 179 180 [StructLayout(LayoutKind.Explicit, Size=RecordSize)] 181 private struct EtherBoneRecord 182 { 183 // here we have a problem with byte order - see FixFieldEndianess 184 [FieldOffset(0)] public ushort Magic; 185 [FieldOffset(2)] public byte VersionAndFlags; 186 [FieldOffset(3)] public byte AddressAndPortWidth; 187 188 [FieldOffset(8)] public byte WishboneFlags; 189 [FieldOffset(9)] public byte ByteEnable; 190 191 [FieldOffset(10)] public byte WritesCount; 192 [FieldOffset(11)] public byte ReadsCount; 193 194 [FieldOffset(12)] public uint ReadValueWriteAddress; 195 [FieldOffset(16)] public uint WriteValueReadAddress; 196 } 197 198 private const int RecordSize = 20; 199 } 200 } 201