1 //
2 // Copyright (c) 2010-2022 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;
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.Debugging;
14 using Antmicro.Renode.Exceptions;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Utilities;
18 
19 namespace Antmicro.Renode.Peripherals.I2C
20 {
21     public class OpenTitan_I2C : SimpleContainer<II2CPeripheral>, II2CPeripheral, IDoubleWordPeripheral, IKnownSize
22     {
OpenTitan_I2C(IMachine machine)23         public OpenTitan_I2C(IMachine machine) : base(machine)
24         {
25             FormatWatermarkIRQ = new GPIO();
26             RxWatermarkIRQ = new GPIO();
27             FormatOverflowIRQ = new GPIO();
28             RxOverflowIRQ = new GPIO();
29             NakIRQ = new GPIO();
30             SclInterfaceIRQ = new GPIO();
31             SdaInterfaceIRQ = new GPIO();
32             StretchTimeoutIRQ = new GPIO();
33             SdaUnstableIRQ = new GPIO();
34             TransactionCompleteIRQ = new GPIO();
35             TxEmptyIRQ = new GPIO();
36             TxNonEmptyIRQ = new GPIO();
37             TxOverflowIRQ = new GPIO();
38             AcqOverflowIRQ = new GPIO();
39             AckAfterStopIRQ = new GPIO();
40             HostTimeoutIRQ = new GPIO();
41 
42             FatalAlert = new GPIO();
43 
44             acquiredFifo = new Queue<AcquireFormatIndicator>();
45             formatFifo = new Queue<FormatIndicator>();
46             rxFifo = new Queue<byte>();
47             txFifo = new Queue<byte>();
48 
49             var registers = new Dictionary<long, DoubleWordRegister>
50             {
51                 {(long)Registers.InterruptState, new DoubleWordRegister(this, 0x0)
52                     .WithFlag(0,  out formatWatermarkInterruptState,     FieldMode.Read | FieldMode.WriteOneToClear, name: "fmt_watermark")
53                     .WithFlag(1,  out rxWatermarkInterruptState,         FieldMode.Read | FieldMode.WriteOneToClear, name: "rx_watermark")
54                     .WithFlag(2,  out formatOverflowInterruptState,      FieldMode.Read | FieldMode.WriteOneToClear, name: "fmt_overflow")
55                     .WithFlag(3,  out rxOverflowInterruptState,          FieldMode.Read | FieldMode.WriteOneToClear, name: "rx_overflow")
56                     .WithFlag(4,  out nakInterruptState,                 FieldMode.Read | FieldMode.WriteOneToClear, name: "nak")
57                     .WithFlag(5,  out sclInterfaceInterruptState,        FieldMode.Read | FieldMode.WriteOneToClear, name: "scl_interference")
58                     .WithFlag(6,  out sdaInterfaceInterruptState,        FieldMode.Read | FieldMode.WriteOneToClear, name: "sda_interference")
59                     .WithFlag(7,  out stretchTimeoutInterruptState,      FieldMode.Read | FieldMode.WriteOneToClear, name: "stretch_timeout")
60                     .WithFlag(8,  out sdaUnstableInterruptState,         FieldMode.Read | FieldMode.WriteOneToClear, name: "sda_unstable")
61                     .WithFlag(9,  out transactionCompleteInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "trans_complete")
62                     .WithFlag(10, out txEmptyInterruptState,             FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_empty")
63                     .WithFlag(11, out txNonEmptyInterruptState,          FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_nonempty")
64                     .WithFlag(12, out txOverflowInterruptState,          FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_overflow")
65                     .WithFlag(13, out acqOverflowInterruptState,         FieldMode.Read | FieldMode.WriteOneToClear, name: "acq_overflow")
66                     .WithFlag(14, out ackAfterStopInterruptState,        FieldMode.Read | FieldMode.WriteOneToClear, name: "ack_stop")
67                     .WithFlag(15, out hostTimeoutInterruptState,         FieldMode.Read | FieldMode.WriteOneToClear, name: "host_timeout")
68                     .WithReservedBits(16, 16)
69                     .WithChangeCallback((_, __) => UpdateInterrupts())
70                 },
71 
72                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this, 0x0)
73                     .WithFlag(0,  out formatWatermarkInterruptEnable,     name: "fmt_watermark")
74                     .WithFlag(1,  out rxWatermarkInterruptEnable,         name: "rx_watermark")
75                     .WithFlag(2,  out formatOverflowInterruptEnable,      name: "fmt_overflow")
76                     .WithFlag(3,  out rxOverflowInterruptEnable,          name: "rx_overflow")
77                     .WithFlag(4,  out nakInterruptEnable,                 name: "nak")
78                     .WithFlag(5,  out sclInterfaceInterruptEnable,        name: "scl_interference")
79                     .WithFlag(6,  out sdaInterfaceInterruptEnable,        name: "sda_interference")
80                     .WithFlag(7,  out stretchTimeoutInterruptEnable,      name: "stretch_timeout")
81                     .WithFlag(8,  out sdaUnstableInterruptEnable,         name: "sda_unstable")
82                     .WithFlag(9,  out transactionCompleteInterruptEnable, name: "trans_complete")
83                     .WithFlag(10, out txEmptyInterruptEnable,             name: "tx_empty")
84                     .WithFlag(11, out txNonEmptyInterruptEnable,          name: "tx_nonempty")
85                     .WithFlag(12, out txOverflowInterruptEnable,          name: "tx_overflow")
86                     .WithFlag(13, out acqOverflowInterruptEnable,         name: "acq_overflow")
87                     .WithFlag(14, out ackAfterStopInterruptEnable,        name: "ack_stop")
88                     .WithFlag(15, out hostTimeoutInterruptEnable,         name: "host_timeout")
89                     .WithReservedBits(16, 16)
90                     .WithChangeCallback((_, __) => UpdateInterrupts())
91                 },
92 
93                 {(long)Registers.InterruptTest, new DoubleWordRegister(this, 0x0)
94                     .WithFlag(0,  FieldMode.Write, writeCallback: (_, val) => { if(val) formatWatermarkInterruptState.Value = true; },     name: "fmt_watermark")
95                     .WithFlag(1,  FieldMode.Write, writeCallback: (_, val) => { if(val) rxWatermarkInterruptState.Value = true; },         name: "rx_watermark")
96                     .WithFlag(2,  FieldMode.Write, writeCallback: (_, val) => { if(val) formatOverflowInterruptState.Value = true; },      name: "fmt_overflow")
97                     .WithFlag(3,  FieldMode.Write, writeCallback: (_, val) => { if(val) rxOverflowInterruptState.Value = true; },          name: "rx_overflow")
98                     .WithFlag(4,  FieldMode.Write, writeCallback: (_, val) => { if(val) nakInterruptState.Value = true; },                 name: "nak")
99                     .WithFlag(5,  FieldMode.Write, writeCallback: (_, val) => { if(val) sclInterfaceInterruptState.Value = true; },        name: "scl_interference")
100                     .WithFlag(6,  FieldMode.Write, writeCallback: (_, val) => { if(val) sdaInterfaceInterruptState.Value = true; },        name: "sda_interference")
101                     .WithFlag(7,  FieldMode.Write, writeCallback: (_, val) => { if(val) stretchTimeoutInterruptState.Value = true; },      name: "stretch_timeout")
102                     .WithFlag(8,  FieldMode.Write, writeCallback: (_, val) => { if(val) sdaUnstableInterruptState.Value = true; },         name: "sda_unstable")
103                     .WithFlag(9,  FieldMode.Write, writeCallback: (_, val) => { if(val) transactionCompleteInterruptState.Value = true; }, name: "trans_complete")
104                     .WithFlag(10, FieldMode.Write, writeCallback: (_, val) => { if(val) txEmptyInterruptState.Value = true; },             name: "tx_empty")
105                     .WithFlag(11, FieldMode.Write, writeCallback: (_, val) => { if(val) txNonEmptyInterruptState.Value = true; },          name: "tx_nonempty")
106                     .WithFlag(12, FieldMode.Write, writeCallback: (_, val) => { if(val) txOverflowInterruptState.Value = true; },          name: "tx_overflow")
107                     .WithFlag(13, FieldMode.Write, writeCallback: (_, val) => { if(val) acqOverflowInterruptState.Value = true; },         name: "acq_overflow")
108                     .WithFlag(14, FieldMode.Write, writeCallback: (_, val) => { if(val) ackAfterStopInterruptState.Value = true; },        name: "ack_stop")
109                     .WithFlag(15, FieldMode.Write, writeCallback: (_, val) => { if(val) hostTimeoutInterruptState.Value = true; },         name: "host_timeout")
110                     .WithReservedBits(16,16)
111                     .WithChangeCallback((_, __) => UpdateInterrupts())
112                 },
113 
114                 {(long)Registers.AlertTest, new DoubleWordRegister(this, 0x0)
115                     .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
116                     .WithReservedBits(1, 31)
117                 },
118 
119                 {(long)Registers.Control, new DoubleWordRegister(this, 0x0)
120                     .WithFlag(0, out enabledHost, name: "ENABLEHOST")
121                     .WithFlag(1, out enabledTarget, name: "ENABLETARGET")
122                     .WithTaggedFlag("LLPBK", 2)
123                     .WithReservedBits(3, 29)
124                     .WithWriteCallback((_, __) => {
125                         if(enabledHost.Value && enabledTarget.Value)
126                         {
127                             this.Log(LogLevel.Warning, "This peripheral does not support working in both target and host mode in the same time. " +
128                                                         "The mode is now set to the host mode.");
129                             enabledHost.Value = true;
130                             enabledTarget.Value = false;
131                         }
132                         this.NoisyLog("The mode set to {0}", enabledHost.Value ? "host" : (enabledTarget.Value ? "target" : "none"));
133                         if(enabledHost.Value)
134                         {
135                             ExecuteCommands();
136                         }
137                     })
138                 },
139 
140                 {(long)Registers.Status, new DoubleWordRegister(this, 0x3c )
141                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => (formatFifo.Count == MaximumFifoDepth), name: "FMTFULL")
142                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => (rxFifo.Count == MaximumFifoDepth), name: "RXFULL")
143                     .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => (formatFifo.Count == 0), name: "FMTEMPTY")
144                     .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => true, name: "HOSTIDLE")
145                     .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => true, name: "TARGETIDLE")
146                     .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => (rxFifo.Count == 0), name: "RXEMPTY")
147                     .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => (txFifo.Count == MaximumFifoDepth), name: "TXFULL")
148                     .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => (acquiredFifo.Count == MaximumFifoDepth), name: "ACQFULL")
149                     .WithFlag(8, FieldMode.Read, valueProviderCallback: _ => (txFifo.Count == 0), name: "TXEMPTY")
150                     .WithFlag(9, FieldMode.Read, valueProviderCallback: _ => (acquiredFifo.Count == 0), name: "ACQEMPTY")
151                     .WithReservedBits(10, 22)
152                 },
153 
154                 {(long)Registers.ReadData, new DoubleWordRegister(this, 0x0)
155                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ =>
156                         {
157                             if(!Misc.TryDequeue(rxFifo, out var value))
158                             {
159                                 this.Log(LogLevel.Error, "Queue empty, not able to dequeue");
160                             }
161                             return value;
162                         }, name: "RDATA")
163                     .WithReservedBits(8, 24)
164                 },
165 
166                 {(long)Registers.FormatData, new DoubleWordRegister(this, 0x0)
167                     .WithValueField(0, 8, out formatByte, name: "FBYTE")
168                     .WithFlag(8, out startFlag, name: "START")
169                     .WithFlag(9, out stopFlag, name: "STOP")
170                     .WithFlag(10, out readFlag, name: "READ")
171                     .WithFlag(11, out readContinueFlag, name: "RCONT")
172                     .WithFlag(12, out nakOkFlag, name: "NAKOK")
173                     .WithReservedBits(13, 19)
174                     .WithWriteCallback((_, __) => EnqueueFormat())
175                 },
176 
177                 {(long)Registers.FifoControl, new DoubleWordRegister(this, 0x0)
178                     .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) rxFifo.Clear(); }, name: "RXRST")
179                     .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) formatFifo.Clear(); }, name: "FMTRST")
180                     .WithEnumField<DoubleWordRegister, WatermarkLevel>(2, 3, out rxWatermarkLevel, name: "RXILVL")
181                     .WithEnumField<DoubleWordRegister, WatermarkLevel>(5, 2, out fmtWatermarkLevel, name: "FMTILVL_FIELD")
182                     .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { if(val) acquiredFifo.Clear(); }, name:"ACQRST")
183                     .WithFlag(8, FieldMode.Write, writeCallback: (_, val) => { if(val) txFifo.Clear(); }, name:"TXRST")
184                     .WithReservedBits(9, 23)
185                     .WithWriteCallback((_, __) => UpdateWatermarks())
186                  },
187 
188                 {(long)Registers.FifoStatus, new DoubleWordRegister(this, 0x0)
189                     .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)formatFifo.Count, name: "FMTLVL")
190                     .WithReservedBits(7, 1)
191                     .WithValueField(8, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)txFifo.Count, name: "TXLVL")
192                     .WithReservedBits(15, 1)
193                     .WithValueField(16, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)rxFifo.Count, name: "RXLVL")
194                     .WithReservedBits(23, 1)
195                     .WithValueField(24, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)acquiredFifo.Count, name:"ACQLVL")
196                     .WithReservedBits(31, 1)
197                  },
198 
199                 {(long)Registers.OverrideControl, new DoubleWordRegister(this, 0x0)
200                     .WithTaggedFlag("TXOVRDEN", 0)
201                     .WithTaggedFlag("SCLVAL", 1)
202                     .WithTaggedFlag("SDAVAL", 2)
203                     .WithReservedBits(3, 29)
204                  },
205 
206                 {(long)Registers.OversampledValues, new DoubleWordRegister(this, 0x0)
207                     .WithTag("SCL_RX", 0, 16)
208                     .WithTag("SDA_RX", 16, 16)
209                  },
210 
211                 {(long)Registers.Timing0, new DoubleWordRegister(this, 0x0)
212                     .WithTag("THIGH", 0, 16)
213                     .WithTag("TLOW", 16, 16)
214                  },
215 
216                 {(long)Registers.Timing1, new DoubleWordRegister(this, 0x0)
217                     .WithTag("T_R", 0, 16)
218                     .WithTag("T_F", 16, 16)
219                  },
220 
221                 {(long)Registers.Timing2, new DoubleWordRegister(this, 0x0)
222                     .WithTag("TSU_STA", 0, 16)
223                     .WithTag("THD_STA", 16, 16)
224                  },
225 
226                 {(long)Registers.Timing3, new DoubleWordRegister(this, 0x0)
227                     .WithTag("TSU_DAT", 0, 16)
228                     .WithTag("THD_DAT", 16, 16)
229                  },
230 
231                 {(long)Registers.Timing4, new DoubleWordRegister(this, 0x0)
232                     .WithTag("TSU_STO", 0, 16)
233                     .WithTag("T_BUF", 16, 16)
234                  },
235 
236                 {(long)Registers.ClockStrechingTimeout, new DoubleWordRegister(this, 0x0)
237                     .WithTag("VAL", 0, 31)
238                     .WithTaggedFlag("EN", 31)
239                  },
240 
241                 {(long)Registers.TargetId, new DoubleWordRegister(this, 0x0)
242                     .WithTag("ADDRESS0", 0, 7)
243                     .WithTag("MASK0", 7, 7)
244                     .WithTag("ADDRESS1", 14, 7)
245                     .WithTag("MASK1", 21, 7)
246                     .WithReservedBits(28, 4)
247                  },
248 
249                 {(long)Registers.AcquiredData, new DoubleWordRegister(this, 0x0)
250                     .WithValueField(0, 10, FieldMode.Read, valueProviderCallback: (_) =>
251                         {
252                             return acquiredFifo.TryDequeue(out var output) ? output.ToRegisterValue() : 0;
253                         }, name:"ABYTE and SIGNAL")
254                     .WithReservedBits(10, 22)
255                 },
256 
257                 {(long)Registers.TransmitData, new DoubleWordRegister(this, 0x0)
258                     .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) => EnqueueTx((byte)val), name: "TXDATA")
259                     .WithReservedBits(8, 24)
260                  },
261 
262                 {(long)Registers.TargetClockStretching, new DoubleWordRegister(this, 0x0)
263                     .WithTaggedFlag("I2C_STRETCH_CTRL_EN_ADDR_TX", 0)
264                     .WithTaggedFlag("I2C_STRETCH_CTRL_EN_ADDR_ACQ", 1)
265                     .WithTaggedFlag("I2C_STRETCH_CTRL_STOP_TX", 2)
266                     .WithTaggedFlag("I2C_STRETCH_CTRL_STOP_ACQ", 3)
267                     .WithReservedBits(4, 28)
268                 },
269 
270                 {(long)Registers.HostClockGenerationTimeout, new DoubleWordRegister(this, 0x0)
271                     .WithTag("HOST_TIMEOUT_CTRL", 0, 32)
272                 }
273             };
274 
275             acquiredFifo = new Queue<AcquireFormatIndicator>();
276             formatFifo = new Queue<FormatIndicator>();
277             rxFifo = new Queue<byte>();
278             txFifo = new Queue<byte>();
279 
280             registersCollection = new DoubleWordRegisterCollection(this, registers);
281             Reset();
282         }
283 
Reset()284         public override void Reset()
285         {
286             registersCollection.Reset();
287             UpdateWatermarks();
288             ResetBuffers();
289 
290             currentState = State.Idle;
291             transactionAddress = null;
292             selectedSlave = null;
293         }
294 
ReadDoubleWord(long offset)295         public uint ReadDoubleWord(long offset)
296         {
297             return registersCollection.Read(offset);
298         }
299 
WriteDoubleWord(long offset, uint value)300         public void WriteDoubleWord(long offset, uint value)
301         {
302             registersCollection.Write(offset, value);
303         }
304 
305         // Write, Read and FinishTransmission methods are meant to be used only in the target mode
Write(byte[] data)306         public void Write(byte[] data)
307         {
308             if(data.Length == 0)
309             {
310                 return;
311             }
312 
313             var index = 0;
314             if(currentState == State.Idle || currentState == State.Transaction)
315             {
316                 // Handle the start/repeated start byte
317                 EnqueueAcquired(new AcquireFormatIndicator(data[0], start: true, stop: currentState == State.Transaction));
318                 currentState = State.Transaction;
319                 index += 1;
320             }
321             for(; index < data.Length; index++)
322             {
323                 EnqueueAcquired(new AcquireFormatIndicator(data[index], start: false, stop: false));
324             }
325         }
326 
Read(int count)327         public byte[] Read(int count)
328         {
329             var temp = new List<byte>();
330             for(var i = 0; i < count; i++)
331             {
332                 if(!txFifo.TryDequeue(out var data))
333                 {
334                     break;
335                 }
336                 temp.Add(data);
337             }
338             return temp.ToArray();
339         }
340 
FinishTransmission()341         public void FinishTransmission()
342         {
343             if(enabledHost.Value)
344             {
345                 throw new RecoverableException("This should never be called in the host mode");
346             }
347             EnqueueAcquired(new AcquireFormatIndicator(0x0, start: false, stop: true));
348             currentState = State.Idle;
349 
350             transactionCompleteInterruptState.Value = true;
351             UpdateInterrupts();
352         }
353 
354         public long Size => 0x1000;
355 
356         public GPIO FormatWatermarkIRQ { get; }
357         public GPIO RxWatermarkIRQ { get; }
358         public GPIO FormatOverflowIRQ { get; }
359         public GPIO RxOverflowIRQ { get; }
360         public GPIO NakIRQ { get; }
361         public GPIO SclInterfaceIRQ { get; }
362         public GPIO SdaInterfaceIRQ { get; }
363         public GPIO StretchTimeoutIRQ { get; }
364         public GPIO SdaUnstableIRQ { get; }
365         public GPIO TransactionCompleteIRQ { get; }
366         public GPIO TxEmptyIRQ { get; }
367         public GPIO TxNonEmptyIRQ { get; }
368         public GPIO TxOverflowIRQ { get; }
369         public GPIO AcqOverflowIRQ { get; }
370         public GPIO AckAfterStopIRQ { get; }
371         public GPIO HostTimeoutIRQ { get; }
372 
373         public GPIO FatalAlert { get; }
374 
UpdateInterrupts()375         private void UpdateInterrupts()
376         {
377             FormatWatermarkIRQ.Set(formatWatermarkInterruptState.Value && formatWatermarkInterruptEnable.Value);
378             RxWatermarkIRQ.Set(rxWatermarkInterruptState.Value && rxWatermarkInterruptEnable.Value);
379             FormatOverflowIRQ.Set(formatOverflowInterruptState.Value && formatOverflowInterruptEnable.Value);
380             RxOverflowIRQ.Set(rxOverflowInterruptState.Value && rxOverflowInterruptEnable.Value);
381             NakIRQ.Set(nakInterruptState.Value && nakInterruptEnable.Value);
382             SclInterfaceIRQ.Set(sclInterfaceInterruptState.Value && sclInterfaceInterruptEnable.Value);
383             SdaInterfaceIRQ.Set(sdaInterfaceInterruptState.Value && sdaInterfaceInterruptEnable.Value);
384             StretchTimeoutIRQ.Set(stretchTimeoutInterruptState.Value && stretchTimeoutInterruptEnable.Value);
385             SdaUnstableIRQ.Set(sdaUnstableInterruptState.Value && sdaUnstableInterruptEnable.Value);
386             TransactionCompleteIRQ.Set(transactionCompleteInterruptState.Value && transactionCompleteInterruptEnable.Value);
387             TxEmptyIRQ.Set(txEmptyInterruptState.Value && txEmptyInterruptEnable.Value);
388             TxNonEmptyIRQ.Set(txNonEmptyInterruptState.Value && txNonEmptyInterruptEnable.Value);
389             TxOverflowIRQ.Set(txOverflowInterruptState.Value && txOverflowInterruptEnable.Value);
390             AcqOverflowIRQ.Set(acqOverflowInterruptState.Value && acqOverflowInterruptEnable.Value);
391             AckAfterStopIRQ.Set(ackAfterStopInterruptState.Value && ackAfterStopInterruptEnable.Value);
392             HostTimeoutIRQ.Set(hostTimeoutInterruptState.Value && hostTimeoutInterruptEnable.Value);
393         }
394 
UpdateWatermarks()395         private void UpdateWatermarks()
396         {
397             fmtWatermark = WatermarkEnumToValue(fmtWatermarkLevel.Value);
398             rxWatermark = WatermarkEnumToValue(rxWatermarkLevel.Value);
399         }
400 
WatermarkEnumToValue(WatermarkLevel value)401         private uint WatermarkEnumToValue(WatermarkLevel value)
402         {
403             switch(value)
404             {
405                 case WatermarkLevel.Char1:
406                     return 1;
407                 case WatermarkLevel.Char4:
408                     return 4;
409                 case WatermarkLevel.Char8:
410                     return 8;
411                 case WatermarkLevel.Char16:
412                     return 16;
413                 default:
414                     throw new ArgumentException("Illegal value");
415             }
416         }
417 
ExecuteCommands()418         private void ExecuteCommands()
419         {
420             if(enabledTarget.Value)
421             {
422                 throw new ApplicationException("This should not be possible in the target mode");
423             }
424             this.NoisyLog("Executing queued commands");
425             while(formatFifo.Count > 0)
426             {
427                 HandleCommand(formatFifo.Dequeue());
428             }
429         }
430 
HandleCommand(FormatIndicator command)431         private void HandleCommand(FormatIndicator command)
432         {
433             DebugHelper.Assert(selectedSlave != null || currentState == State.Idle, $"Cannot have no selected slave in the state {currentState}. This should have never happend");
434 
435             switch(currentState)
436             {
437                 case State.Idle:
438                     if(!command.StartOnly)
439                     {
440                         this.Log(LogLevel.Error, "Only a format code with a start is accepted in the idle state");
441                         return;
442                     }
443                     if(!TryGetByAddress(command.Data, out selectedSlave))
444                     {
445                         this.Log(LogLevel.Error, "No device available under address {0}. All further transactions until STOP will be ignored", command.Data);
446                         nakInterruptState.Value = true;
447                         UpdateInterrupts();
448                         currentState = State.Error;
449                         return;
450                     }
451                     currentState = State.AwaitingAddress;
452                     break;
453                 case State.AwaitingAddress:
454                     if(!command.NoFlags)
455                     {
456                         this.Log(LogLevel.Error, "Expected slave address, but some of the flags are set [{0}]. Skipping", command.FlagsToString());
457                         return;
458                     }
459                     transactionAddress = (byte)command.Data;
460                     currentState = State.Transaction;
461                     break;
462                 case State.Transaction:
463                     if(command.IsRead)
464                     {
465                         ReadFromSlave(command.Data);
466                     }
467                     else if(command.NoFlags)
468                     {
469                         WriteToSlave(command.Data);
470                     }
471                     else
472                     {
473                         this.Log(LogLevel.Error, "Incorrect command in the 'Transaction' state. Expected read flag, or no flag when writing. Flags set: {0}", command.FlagsToString());
474                         return;
475                     }
476 
477                     if(command.StopFlag)
478                     {
479                         selectedSlave.FinishTransmission();
480                         CleanupTransaction();
481                     }
482                     break;
483                 case State.Error:
484                     if(command.StopFlag)
485                     {
486                         CleanupTransaction();
487                     }
488                     break;
489                 default:
490                     throw new ArgumentException($"Illegal state: {currentState}");
491             }
492         }
493 
CleanupTransaction()494         private void CleanupTransaction()
495         {
496             transactionAddress = null;
497             selectedSlave = null;
498             currentState = State.Idle;
499         }
500 
ReadFromSlave(byte count)501         private void ReadFromSlave(byte count)
502         {
503             // Specification does not allow a zero value - it is treated as a 256
504             var bytesCount = (count == 0) ? 256 : count;
505             selectedSlave.Write(new byte[] { transactionAddress.Value });
506             foreach(var b in selectedSlave.Read(bytesCount))
507             {
508                 EnqueueRx(b);
509             }
510         }
511 
WriteToSlave(byte data)512         private void WriteToSlave(byte data)
513         {
514             DebugHelper.Assert(transactionAddress != null, "Address not selected when performing read operation.");
515 
516             selectedSlave.Write(new byte[] { transactionAddress.Value, data });
517         }
518 
HandleEnqueue(Queue<T> queue, T value, IFlagRegisterField overflowInterrupt = null, IFlagRegisterField watermarkInterrupt = null, uint watermarkLevel = 0)519         private void HandleEnqueue<T>(Queue<T> queue, T value, IFlagRegisterField overflowInterrupt = null,
520                                       IFlagRegisterField watermarkInterrupt = null, uint watermarkLevel = 0)
521         {
522             if(queue.Count == MaximumFifoDepth && overflowInterrupt != null)
523             {
524                 overflowInterrupt.Value = true;
525                 UpdateInterrupts();
526                 this.Log(LogLevel.Warning, "Fifo {0} is at its maximum capacity of {1} elements. Dropping incoming element", queue.GetType().Name, MaximumFifoDepth);
527                 return;
528             }
529             queue.Enqueue(value);
530             if(watermarkInterrupt != null && queue.Count == watermarkLevel)
531             {
532                 watermarkInterrupt.Value = true;
533                 UpdateInterrupts();
534             }
535         }
536 
EnqueueFormat()537         private void EnqueueFormat()
538         {
539             if(enabledTarget.Value)
540             {
541                 this.Log(LogLevel.Warning, "Cannot enqueue commands when in target mode.");
542                 return;
543             }
544             var format = new FormatIndicator((byte)formatByte.Value, startFlag.Value, stopFlag.Value, readFlag.Value, readContinueFlag.Value,
545                                              nakOkFlag.Value);
546             HandleEnqueue(formatFifo, format, formatOverflowInterruptState, formatWatermarkInterruptState, fmtWatermark);
547             this.Log(LogLevel.Noisy, "Enqueued format data: {0}", format);
548             if(enabledHost.Value)
549             {
550                 ExecuteCommands();
551             }
552         }
553 
EnqueueAcquired(AcquireFormatIndicator acquired)554         private void EnqueueAcquired(AcquireFormatIndicator acquired)
555         {
556             if(enabledHost.Value)
557             {
558                 this.Log(LogLevel.Warning, "Cannot enqueue acquired data when in target mode");
559                 return;
560             }
561             HandleEnqueue(acquiredFifo, acquired, acqOverflowInterruptState);
562         }
563 
EnqueueRx(uint value)564         private void EnqueueRx(uint value)
565         {
566             HandleEnqueue(rxFifo, (byte)value, rxOverflowInterruptState, rxWatermarkInterruptState, rxWatermark);
567         }
568 
EnqueueTx(byte value)569         private void EnqueueTx(byte value)
570         {
571             if(enabledHost.Value)
572             {
573                 this.Log(LogLevel.Warning, "Tried to enqueue byte 0x{0:X} to the Tx fifo in the host mode. Tx Fifo is available only in the target mode");
574                 return;
575             }
576             HandleEnqueue(txFifo, value, txOverflowInterruptState);
577         }
578 
ResetBuffers()579         private void ResetBuffers()
580         {
581             rxFifo.Clear();
582             acquiredFifo.Clear();
583             formatFifo.Clear();
584             txFifo.Clear();
585         }
586 
587         private IFlagRegisterField formatWatermarkInterruptState;
588         private IFlagRegisterField rxWatermarkInterruptState;
589         private IFlagRegisterField formatOverflowInterruptState;
590         private IFlagRegisterField rxOverflowInterruptState;
591         private IFlagRegisterField nakInterruptState;
592         private IFlagRegisterField sclInterfaceInterruptState;
593         private IFlagRegisterField sdaInterfaceInterruptState;
594         private IFlagRegisterField stretchTimeoutInterruptState;
595         private IFlagRegisterField sdaUnstableInterruptState;
596         private IFlagRegisterField transactionCompleteInterruptState;
597         private IFlagRegisterField txEmptyInterruptState;
598         private IFlagRegisterField txNonEmptyInterruptState;
599         private IFlagRegisterField txOverflowInterruptState;
600         private IFlagRegisterField acqOverflowInterruptState;
601         private IFlagRegisterField ackAfterStopInterruptState;
602         private IFlagRegisterField hostTimeoutInterruptState;
603         private IFlagRegisterField formatWatermarkInterruptEnable;
604         private IFlagRegisterField rxWatermarkInterruptEnable;
605         private IFlagRegisterField formatOverflowInterruptEnable;
606         private IFlagRegisterField rxOverflowInterruptEnable;
607         private IFlagRegisterField nakInterruptEnable;
608         private IFlagRegisterField sclInterfaceInterruptEnable;
609         private IFlagRegisterField sdaInterfaceInterruptEnable;
610         private IFlagRegisterField stretchTimeoutInterruptEnable;
611         private IFlagRegisterField sdaUnstableInterruptEnable;
612         private IFlagRegisterField transactionCompleteInterruptEnable;
613         private IFlagRegisterField txEmptyInterruptEnable;
614         private IFlagRegisterField txNonEmptyInterruptEnable;
615         private IFlagRegisterField txOverflowInterruptEnable;
616         private IFlagRegisterField acqOverflowInterruptEnable;
617         private IFlagRegisterField ackAfterStopInterruptEnable;
618         private IFlagRegisterField hostTimeoutInterruptEnable;
619 
620         private IFlagRegisterField enabledHost;
621         private IFlagRegisterField enabledTarget;
622         private IFlagRegisterField startFlag;
623         private IFlagRegisterField stopFlag;
624         private IFlagRegisterField readFlag;
625         private IFlagRegisterField readContinueFlag;
626         private IFlagRegisterField nakOkFlag;
627         private IValueRegisterField formatByte;
628 
629         private IEnumRegisterField<WatermarkLevel> rxWatermarkLevel;
630         private IEnumRegisterField<WatermarkLevel> fmtWatermarkLevel;
631         private uint rxWatermark;
632         private uint fmtWatermark;
633 
634         private readonly DoubleWordRegisterCollection registersCollection;
635         private readonly Queue<FormatIndicator> formatFifo;
636         private readonly Queue<AcquireFormatIndicator> acquiredFifo;
637         private readonly Queue<byte> rxFifo;
638         private readonly Queue<byte> txFifo;
639 
640         private II2CPeripheral selectedSlave;
641         private byte? transactionAddress;
642         private State currentState;
643 
644         private const int MaximumFifoDepth = 64;
645 
646         public enum Registers
647         {
648             InterruptState = 0x0,
649             InterruptEnable = 0x4,
650             InterruptTest = 0x8,
651             AlertTest = 0xc,
652             Control = 0x10,
653             Status = 0x14,
654             ReadData = 0x18,
655             FormatData = 0x1c,
656             FifoControl = 0x20,
657             FifoStatus = 0x24,
658             OverrideControl = 0x28,
659             OversampledValues = 0x2c,
660             Timing0 = 0x30,
661             Timing1 = 0x34,
662             Timing2 = 0x38,
663             Timing3 = 0x3c,
664             Timing4 = 0x40,
665             ClockStrechingTimeout = 0x44,
666             TargetId = 0x48,
667             AcquiredData = 0x4c,
668             TransmitData = 0x50,
669             TargetClockStretching = 0x54,
670             HostClockGenerationTimeout = 0x58,
671         }
672 
673         public struct AcquireFormatIndicator
674         {
AcquireFormatIndicatorAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator675             public AcquireFormatIndicator(byte data, bool start, bool stop)
676             {
677                 this.Data = data;
678                 if(start)
679                 {
680                     ReadFlag = ((data & 0x1) == 1);
681                 }
682                 else
683                 {
684                     ReadFlag = false;
685                 }
686                 this.StartFlag = start;
687                 this.StopFlag = stop;
688             }
689 
ToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator690             public override string ToString()
691             {
692                 return $"{Data:X2} with start: {StartFlag}, stop: {StopFlag}, read: {ReadFlag}";
693             }
694 
ToRegisterValueAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator695             public uint ToRegisterValue()
696             {
697                 uint flags = (StartFlag ? 1u : 0u) | ((StopFlag ? 1u : 0u) << 1);
698                 return (uint)Data | (flags << 8);
699             }
700 
FromRegisterAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator701             public static AcquireFormatIndicator FromRegister(uint registerValue)
702             {
703                 var data = (byte)registerValue;
704 
705                 var startFlag = ((registerValue >> 8) & 1) == 1;
706                 var stopFlag = ((registerValue >> 9) & 1) == 1;
707 
708                 return new AcquireFormatIndicator(data, start: startFlag, stop: stopFlag);
709             }
710 
711             public byte Data { get; }
712             public bool ReadFlag { get; }
713             public bool StartFlag { get; }
714             public bool StopFlag { get; }
715         }
716 
717         public struct FormatIndicator
718         {
FormatIndicatorAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator719             public FormatIndicator(byte data, bool start = false, bool stop = false, bool read = false, bool readContinue = false, bool nakOk = false)
720             {
721                 this.Data = data;
722                 this.ReadFlag = read;
723                 this.ReadContinueFlag = readContinue;
724                 this.StartFlag = start;
725                 this.StopFlag = stop;
726                 this.NakOkFlag = nakOk;
727             }
728 
729             public byte Data { get; }
730             public bool ReadFlag { get; }
731             public bool ReadContinueFlag { get; }
732             public bool StartFlag { get; }
733             public bool StopFlag { get; }
734             public bool NakOkFlag { get; }
735 
736             public bool StartOnly => StopFlag == false && ReadFlag == false && ReadContinueFlag == false && StartFlag == true;
737             public bool IsRead => ReadFlag == true || ReadContinueFlag == true;
738             public bool NoFlags => StopFlag == false && ReadFlag == false && ReadContinueFlag == false && StartFlag == false;
739 
ToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator740             public override string ToString()
741             {
742                 return $"{Data:X2} with {FlagsToString()}";
743             }
744 
FlagsToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator745             public string FlagsToString()
746             {
747                 return $"start:{StartFlag}, stop:{StopFlag}, read:{ReadFlag}, readContinue:{ReadContinueFlag}, nakOk:{NakOkFlag}";
748             }
749 
ToRegisterFormatAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator750             public uint ToRegisterFormat()
751             {
752                 var flags = ((StartFlag ? 1 : 0) << 0) |
753                             ((StopFlag ? 1 : 0) << 1) |
754                             ((ReadFlag ? 1 : 0) << 2) |
755                             ((ReadContinueFlag ? 1 : 0) << 3) |
756                             ((NakOkFlag ? 1 : 0) << 4);
757                 return (uint)(Data | (flags << 8));
758             }
759         }
760 
761         private enum WatermarkLevel
762         {
763             Char1 = 0x0,
764             Char4 = 0x1,
765             Char8 = 0x2,
766             Char16 = 0x3,
767             Char30 = 0x4,
768         }
769 
770         private enum State
771         {
772             Idle,
773             AwaitingAddress,
774             Transaction,
775             Error,
776         }
777     }
778 }
779