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