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 using System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Peripherals.SPI;
16 using Antmicro.Renode.Utilities;
17 
18 namespace Antmicro.Renode.Peripherals.UART.Silabs
19 {
20     public abstract class EFR32_GenericUSART : UARTBase, IUARTWithBufferState, IPeripheralContainer<ISPIPeripheral, NullRegistrationPoint>
21     {
EFR32_GenericUSART(IMachine machine, uint clockFrequency)22         public EFR32_GenericUSART(IMachine machine, uint clockFrequency) : base(machine)
23         {
24             TransmitIRQ = new GPIO();
25             ReceiveIRQ = new GPIO();
26             RxDataAvailableRequest = new GPIO();
27             RxDataAvailableSingleRequest = new GPIO();
28             TxBufferLowRequest = new GPIO();
29             TxBufferLowSingleRequest = new GPIO();
30             TxEmptyRequest = new GPIO();
31             RxDataAvailableRightRequest = new GPIO();
32             RxDataAvailableRightSingleRequest = new GPIO();
33             TxBufferLowRightRequest = new GPIO();
34             TxBufferLowRightSingleRequest = new GPIO();
35             TxEmptyRequest.Set(true);
36             TxBufferLowRequest.Set(true);
37 
38             interruptsManager = new InterruptManager<Interrupt>(this);
39 
40             uartClockFrequency = clockFrequency;
41         }
42 
Reset()43         public override void Reset()
44         {
45             base.Reset();
46             interruptsManager.Reset();
47             spiSlaveDevice = null;
48             TxEmptyRequest.Set(true);
49             TxBufferLowRequest.Set(true);
50         }
51 
Register(ISPIPeripheral peripheral, NullRegistrationPoint registrationPoint)52         public void Register(ISPIPeripheral peripheral, NullRegistrationPoint registrationPoint)
53         {
54             if(spiSlaveDevice != null)
55             {
56                 throw new RegistrationException("Cannot register more than one peripheral.");
57             }
58             Machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
59             spiSlaveDevice = peripheral;
60         }
61 
Unregister(ISPIPeripheral peripheral)62         public void Unregister(ISPIPeripheral peripheral)
63         {
64             if(peripheral != spiSlaveDevice)
65             {
66                 throw new RegistrationException("Trying to unregister not registered device.");
67             }
68 
69             Machine.UnregisterAsAChildOf(this, peripheral);
70             spiSlaveDevice = null;
71         }
72 
GetRegistrationPoints(ISPIPeripheral peripheral)73         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(ISPIPeripheral peripheral)
74         {
75             if(peripheral != spiSlaveDevice)
76             {
77                 throw new RegistrationException("Trying to obtain a registration point for a not registered device.");
78             }
79 
80             return new[] { NullRegistrationPoint.Instance };
81         }
82 
WriteChar(byte value)83         public override void WriteChar(byte value)
84         {
85             if(BufferState == BufferState.Full)
86             {
87                 this.Log(LogLevel.Warning, "RX buffer is full. Dropping incoming byte (0x{0:X})", value);
88                 return;
89             }
90             base.WriteChar(value);
91         }
92 
93         IEnumerable<IRegistered<ISPIPeripheral, NullRegistrationPoint>> IPeripheralContainer<ISPIPeripheral, NullRegistrationPoint>.Children
94         {
95             get
96             {
97                 return new[] { Registered.Create(spiSlaveDevice, NullRegistrationPoint.Instance) };
98             }
99         }
100 
101         [IrqProvider("transmit irq", 0)]
102         public GPIO TransmitIRQ { get; }
103 
104         [IrqProvider("receive irq", 1)]
105         public GPIO ReceiveIRQ { get; }
106 
107         public GPIO RxDataAvailableRequest { get; }
108         public GPIO RxDataAvailableSingleRequest { get; }
109         public GPIO TxBufferLowRequest { get; }
110         public GPIO TxBufferLowSingleRequest { get; }
111         public GPIO TxEmptyRequest { get; }
112         public GPIO RxDataAvailableRightRequest { get; }
113         public GPIO RxDataAvailableRightSingleRequest { get; }
114         public GPIO TxBufferLowRightRequest { get; }
115         public GPIO TxBufferLowRightSingleRequest { get; }
116 
117         public override Parity ParityBit { get { return parityBitModeField.Value; } }
118 
119         public override Bits StopBits { get { return stopBitsModeField.Value; } }
120 
121         public override uint BaudRate
122         {
123             get
124             {
125                 //This calculation, according to the documentation, could be written as:
126                 //return uartClockFrequency / (multiplier * (1 + (fractionalClockDividerField.Value << 3) / 256));
127                 //But the result differs much from the one calculated by the driver, most probably due to
128                 //invalid integer division.
129                 //This code mimics the one in emlib driver.
130                 var oversample = 1u;
131                 var factor = 0u;
132                 switch(oversamplingField.Value)
133                 {
134                     case OversamplingMode.Times16:
135                         oversample = 1;
136                         factor = 256 / 16;
137                         break;
138                     case OversamplingMode.Times8:
139                         oversample = 1;
140                         factor = 256 / 8;
141                         break;
142                     case OversamplingMode.Times6:
143                         oversample = 3;
144                         factor = 256 / 2;
145                         break;
146                     case OversamplingMode.Times4:
147                         oversample = 1;
148                         factor = 256 / 4;
149                         break;
150                 }
151                 var divisor = oversample * (256 + ((uint)fractionalClockDividerField.Value << 3));
152                 var quotient = uartClockFrequency / divisor;
153                 var remainder = uartClockFrequency % divisor;
154                 return (factor * quotient) + (factor * remainder) / divisor;
155             }
156         }
157 
158         public BufferState BufferState
159         {
160             get
161             {
162                 return bufferState;
163             }
164 
165             private set
166             {
167                 if(bufferState == value)
168                 {
169                     return;
170                 }
171                 bufferState = value;
172                 BufferStateChanged?.Invoke(value);
173                 switch(bufferState)
174                 {
175                     case BufferState.Empty:
176                         RxDataAvailableRequest.Set(false);
177                         RxDataAvailableSingleRequest.Set(false);
178                         break;
179                     case BufferState.Ready:
180                         RxDataAvailableRequest.Set(false);
181                         RxDataAvailableSingleRequest.Set(true);
182                         break;
183                     case BufferState.Full:
184                         RxDataAvailableRequest.Set(true);
185                         break;
186                     default:
187                         throw new Exception("Unreachable code. Invalid BufferState value.");
188                 }
189             }
190         }
191 
192         public event Action<BufferState> BufferStateChanged;
193 
CharWritten()194         protected override void CharWritten()
195         {
196             interruptsManager.SetInterrupt(Interrupt.ReceiveDataValid);
197             receiveDataValidFlag.Value = true;
198             BufferState = Count == BufferSize ? BufferState.Full : BufferState.Ready;
199         }
200 
QueueEmptied()201         protected override void QueueEmptied()
202         {
203             interruptsManager.ClearInterrupt(Interrupt.ReceiveDataValid);
204             receiveDataValidFlag.Value = false;
205             BufferState = BufferState.Empty;
206         }
207 
208         protected override bool IsReceiveEnabled => receiverEnableFlag.Value;
209 
GenerateControlRegister()210         protected DoubleWordRegister GenerateControlRegister() => new DoubleWordRegister(this)
211             .WithEnumField(0, 1, out operationModeField, name: "SYNC")
212             .WithTaggedFlag("LOOPBK", 1)
213             .WithTaggedFlag("CCEN", 2)
214             .WithTaggedFlag("MPM", 3)
215             .WithTaggedFlag("MPAB", 4)
216             .WithEnumField(5, 2, out oversamplingField, name: "OVS")
217             .WithReservedBits(7, 1)
218             .WithTaggedFlag("CLKPOL", 8)
219             .WithTaggedFlag("CLKPHA", 9)
220             .WithTaggedFlag("MSBF", 10)
221             .WithTaggedFlag("CSMA", 11)
222             .WithTaggedFlag("TXBIL", 12)
223             .WithTaggedFlag("RXINV", 13)
224             .WithTaggedFlag("TXINV", 14)
225             .WithTaggedFlag("CSINV", 15)
226             .WithTaggedFlag("AUTOCS", 16)
227             .WithTaggedFlag("AUTOTRI", 17)
228             .WithTaggedFlag("SCMODE", 18)
229             .WithTaggedFlag("SCRETRANS", 19)
230             .WithTaggedFlag("SKIPPERRF", 20)
231             .WithTaggedFlag("BIT8DV", 21)
232             .WithTaggedFlag("ERRSDMA", 22)
233             .WithTaggedFlag("ERRSRX", 23)
234             .WithTaggedFlag("ERRSTX", 24)
235             .WithTaggedFlag("SSSEARLY", 25)
236             .WithReservedBits(26, 2)
237             .WithTaggedFlag("BYTESWAP", 28)
238             .WithTaggedFlag("AUTOTX", 29)
239             .WithTaggedFlag("MVDIS", 30)
240             .WithTaggedFlag("SMSDELAY", 31);
241 
GenerateFrameFormatRegister()242         protected DoubleWordRegister GenerateFrameFormatRegister() => new DoubleWordRegister(this, 0x1005)
243             .WithTag("DATABITS", 0, 4)
244             .WithReservedBits(4, 4)
245             .WithEnumField(8, 2, out parityBitModeField, name: "PARITY")
246             .WithReservedBits(10, 2)
247             .WithEnumField(12, 2, out stopBitsModeField, name: "STOPBITS")
248             .WithReservedBits(14, 18);
249 
GenerateTriggerControlRegister()250         protected DoubleWordRegister GenerateTriggerControlRegister() => new DoubleWordRegister(this)
251             .WithReservedBits(0, 4)
252             .WithTaggedFlag("RXTEN", 4)
253             .WithTaggedFlag("TXTEN", 5)
254             .WithTaggedFlag("AUTOTXTEN", 6)
255             .WithTaggedFlag("TXARX0EN", 7)
256             .WithTaggedFlag("TXARX1EN", 8)
257             .WithTaggedFlag("TXARX2EN", 9)
258             .WithTaggedFlag("RXATX0EN", 10)
259             .WithTaggedFlag("RXATX1EN", 11)
260             .WithTaggedFlag("RXATX2EN", 12)
261             .WithReservedBits(13, 3)
262             .WithTag("TSEL", 16, 4)
263             .WithReservedBits(20, 12);
264 
GenerateCommandRegister()265         protected DoubleWordRegister GenerateCommandRegister() => new DoubleWordRegister(this)
266             .WithFlag(0, FieldMode.Set, writeCallback: (_, newValue) => { if(newValue) receiverEnableFlag.Value = true; }, name: "RXEN")
267             .WithFlag(1, FieldMode.Set, writeCallback: (_, newValue) => { if(newValue) receiverEnableFlag.Value = false; }, name: "RXDIS")
268             .WithFlag(2, FieldMode.Set, writeCallback: (_, newValue) =>
269             {
270                 if(newValue)
271                 {
272                     transmitterEnableFlag.Value = true;
273                     interruptsManager.SetInterrupt(Interrupt.TransmitBufferLevel);
274                 }
275             }, name: "TXEN")
276             .WithFlag(3, FieldMode.Set, writeCallback: (_, newValue) => { if(newValue) transmitterEnableFlag.Value = false; }, name: "TXDIS")
277             .WithTaggedFlag("MASTEREN", 4)
278             .WithTaggedFlag("MASTERDIS", 5)
279             .WithTaggedFlag("RXBLOCKEN", 6)
280             .WithTaggedFlag("RXBLOCKDIS", 7)
281             .WithTaggedFlag("TXTRIEN", 8)
282             .WithTaggedFlag("TXTRIDIS", 9)
283             .WithTaggedFlag("CLEARTX", 10)
284             .WithFlag(11, FieldMode.Set, writeCallback: (_, newValue) => { if(newValue) ClearBuffer(); }, name: "CLEARRX")
285             .WithReservedBits(12, 20);
286 
GenerateStatusRegister()287         protected DoubleWordRegister GenerateStatusRegister() => new DoubleWordRegister(this, 0x40)
288             .WithFlag(0, out receiverEnableFlag, FieldMode.Read, name: "RXENS")
289             .WithFlag(1, out transmitterEnableFlag, FieldMode.Read, name: "TXENS")
290             .WithTaggedFlag("MASTER", 2)
291             .WithTaggedFlag("RXBLOCK", 3)
292             .WithTaggedFlag("TXTRI", 4)
293             .WithFlag(5, out transferCompleteFlag, FieldMode.Read, name: "TXC")
294             .WithTaggedFlag("TXBL", 6)
295             .WithFlag(7, out receiveDataValidFlag, FieldMode.Read, name: "RXDATAV")
296             .WithFlag(8, FieldMode.Read, valueProviderCallback: _ => Count == BufferSize, name: "RXFULL")
297             .WithTaggedFlag("TXBDRIGHT", 9)
298             .WithTaggedFlag("TXBSRIGHT", 10)
299             .WithTaggedFlag("RXDATAVRIGHT", 11)
300             .WithTaggedFlag("RXFULLRIGHT", 12)
301             .WithFlag(13, FieldMode.Read, valueProviderCallback: _ => true, name: "TXIDLE")
302             .WithTaggedFlag("TIMERRESTARTED", 14)
303             .WithReservedBits(15, 1)
304             .WithValueField(16, 2, FieldMode.Read, valueProviderCallback: _ => 0, name: "TXBUFCNT")
305             .WithReservedBits(18, 14);
306 
GenerateClockControlRegister()307         protected DoubleWordRegister GenerateClockControlRegister() => new DoubleWordRegister(this)
308             .WithReservedBits(0, 3)
309             .WithValueField(3, 20, out fractionalClockDividerField, name: "DIV")
310             .WithReservedBits(23, 8)
311             .WithTaggedFlag("AUTOBAUDEN", 31);
312 
GenerateRxBufferDataExtendedRegister()313         protected DoubleWordRegister GenerateRxBufferDataExtendedRegister() => new DoubleWordRegister(this)
314             .WithTag("RXDATA", 0, 8)
315             .WithReservedBits(8, 5)
316             .WithTaggedFlag("PERR", 14)
317             .WithTaggedFlag("FERR", 15)
318             .WithReservedBits(16, 16);
319 
GenerateRxBufferDataRegister()320         protected DoubleWordRegister GenerateRxBufferDataRegister() => new DoubleWordRegister(this)
321             .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => ReadBuffer(), name: "RXDATA")
322             .WithReservedBits(8, 24);
323 
GenerateRxBufferDoubleDataExtendedRegister()324         protected DoubleWordRegister GenerateRxBufferDoubleDataExtendedRegister() => new DoubleWordRegister(this)
325             .WithTag("RXDATA0", 0, 8)
326             .WithReservedBits(8, 5)
327             .WithTaggedFlag("PERR0", 14)
328             .WithTaggedFlag("FERR0", 15)
329             .WithTag("RXDATA1", 16, 8)
330             .WithReservedBits(24, 5)
331             .WithTaggedFlag("PERR1", 30)
332             .WithTaggedFlag("FERR1", 31);
333 
GenerateRxBufferDoubleDataRegister()334         protected DoubleWordRegister GenerateRxBufferDoubleDataRegister() => new DoubleWordRegister(this)
335             .WithTag("RXDATA0", 0, 8)
336             .WithTag("RXDATA1", 8, 8)
337             .WithReservedBits(16, 16);
338 
GenerateRxBufferDataExtendedPeekRegister()339         protected DoubleWordRegister GenerateRxBufferDataExtendedPeekRegister() => new DoubleWordRegister(this)
340             .WithTag("RXDATAP", 0, 8)
341             .WithReservedBits(8, 5)
342             .WithTaggedFlag("PERRP", 14)
343             .WithTaggedFlag("FERRP", 15)
344             .WithReservedBits(16, 16);
345 
GenerateRxBufferDoubleDataExtendedPeekRegister()346         protected DoubleWordRegister GenerateRxBufferDoubleDataExtendedPeekRegister() => new DoubleWordRegister(this)
347             .WithTag("RXDATAP0", 0, 8)
348             .WithReservedBits(8, 5)
349             .WithTaggedFlag("PERRP0", 14)
350             .WithTaggedFlag("FERRP0", 15)
351             .WithTag("RXDATAP1", 16, 8)
352             .WithReservedBits(24, 5)
353             .WithTaggedFlag("PERRP1", 30)
354             .WithTaggedFlag("FERRP1", 31);
355 
GenerateTxBufferDataExtendedRegister()356         protected DoubleWordRegister GenerateTxBufferDataExtendedRegister() => new DoubleWordRegister(this)
357             .WithTag("TXDATAX", 0, 8)
358             .WithReservedBits(8, 2)
359             .WithTaggedFlag("UBRXAT", 11)
360             .WithTaggedFlag("TXTRIAT", 12)
361             .WithTaggedFlag("TXBREAK", 13)
362             .WithTaggedFlag("TXDISAT", 14)
363             .WithTaggedFlag("RXENAT", 15)
364             .WithReservedBits(16, 16);
365 
GenerateTxBufferDataRegister()366         protected DoubleWordRegister GenerateTxBufferDataRegister() => new DoubleWordRegister(this)
367             .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, v) => HandleTxBufferData((byte)v), name: "TXDATA")
368             .WithReservedBits(8, 24);
369 
GenerateTxBufferDoubleDataExtendedRegister()370         protected DoubleWordRegister GenerateTxBufferDoubleDataExtendedRegister() => new DoubleWordRegister(this)
371             .WithTag("TXDATA0", 0, 8)
372             .WithReservedBits(8, 2)
373             .WithTaggedFlag("UBRXAT0", 11)
374             .WithTaggedFlag("TXTRIAT0", 12)
375             .WithTaggedFlag("TXBREAK0", 13)
376             .WithTaggedFlag("TXDISAT0", 14)
377             .WithTaggedFlag("RXENAT0", 15)
378             .WithTag("TXDATA1", 16, 8)
379             .WithReservedBits(24, 2)
380             .WithTaggedFlag("UBRXAT1", 27)
381             .WithTaggedFlag("TXTRIAT1", 28)
382             .WithTaggedFlag("TXBREAK1", 29)
383             .WithTaggedFlag("TXDISAT1", 30)
384             .WithTaggedFlag("RXENAT1", 31);
385 
GenerateTxBufferDoubleDataRegister()386         protected DoubleWordRegister GenerateTxBufferDoubleDataRegister() => new DoubleWordRegister(this)
387             .WithTag("TXDATA0", 0, 8)
388             .WithTag("TXDATA1", 8, 8)
389             .WithReservedBits(16, 16);
390 
GenerateIrDAControlRegister()391         protected DoubleWordRegister GenerateIrDAControlRegister() => new DoubleWordRegister(this)
392             .WithTaggedFlag("IREN", 0)
393             .WithTag("IRPW", 1, 2)
394             .WithTaggedFlag("IRFILT", 3)
395             .WithReservedBits(4, 3)
396             .WithTaggedFlag("IRPRSEN", 7)
397             .WithTag("IRPRSSEL", 8, 4)
398             .WithReservedBits(12, 20);
399 
GenerateUSARTInputRegister()400         protected DoubleWordRegister GenerateUSARTInputRegister() => new DoubleWordRegister(this)
401             .WithTag("RXPRSSEL", 0, 4)
402             .WithReservedBits(4, 3)
403             .WithTaggedFlag("RXPRS", 7)
404             .WithTag("CLKPRSSEL", 8, 4)
405             .WithReservedBits(12, 3)
406             .WithTaggedFlag("CLKPRS", 15)
407             .WithReservedBits(16, 16);
408 
GenerateI2SControlRegister()409         protected DoubleWordRegister GenerateI2SControlRegister() => new DoubleWordRegister(this)
410             .WithTaggedFlag("EN", 0)
411             .WithTaggedFlag("MONO", 1)
412             .WithTaggedFlag("JUSTIFY", 2)
413             .WithTaggedFlag("DMASPLIT", 3)
414             .WithTaggedFlag("DELAY", 4)
415             .WithReservedBits(5, 3)
416             .WithTag("FORMAT", 8, 3)
417             .WithReservedBits(11, 21);
418 
GenerateTimingRegister()419         protected DoubleWordRegister GenerateTimingRegister() => new DoubleWordRegister(this)
420             .WithReservedBits(0, 16)
421             .WithTag("TXDELAY", 16, 2)
422             .WithReservedBits(19, 1)
423             .WithTag("CSSETUP", 20, 3)
424             .WithReservedBits(23, 1)
425             .WithTag("ICS", 24, 3)
426             .WithReservedBits(27, 1)
427             .WithTag("CSHOLD", 28, 3)
428             .WithReservedBits(31, 1);
429 
GenerateControlExtendedRegister()430         protected DoubleWordRegister GenerateControlExtendedRegister() => new DoubleWordRegister(this)
431             .WithTaggedFlag("DBHALT", 0)
432             .WithTaggedFlag("CTSINV", 1)
433             .WithTaggedFlag("CTSEN", 2)
434             .WithTaggedFlag("RTSINV", 3)
435             .WithReservedBits(4, 27)
436             .WithTaggedFlag("GPIODELAYXOREN", 31);
437 
GenerateTimeCompare0Register()438         protected DoubleWordRegister GenerateTimeCompare0Register() => new DoubleWordRegister(this)
439             .WithTag("TCMPVAL", 0, 8)
440             .WithReservedBits(8, 8)
441             .WithTag("TSTART", 16, 3)
442             .WithReservedBits(19, 1)
443             .WithTag("TSTOP", 20, 3)
444             .WithReservedBits(23, 1)
445             .WithTaggedFlag("RESTARTEN", 24)
446             .WithReservedBits(25, 7);
447 
GenerateTimeCompare1Register()448         protected DoubleWordRegister GenerateTimeCompare1Register() => new DoubleWordRegister(this)
449             .WithTag("TCMPVAL", 0, 8)
450             .WithReservedBits(8, 8)
451             .WithTag("TSTART", 16, 3)
452             .WithReservedBits(19, 1)
453             .WithTag("TSTOP", 20, 3)
454             .WithReservedBits(23, 1)
455             .WithTaggedFlag("RESTARTEN", 24)
456             .WithReservedBits(25, 7);
457 
GenerateTimeCompare2Register()458         protected DoubleWordRegister GenerateTimeCompare2Register() => new DoubleWordRegister(this)
459             .WithTag("TCMPVAL", 0, 8)
460             .WithReservedBits(8, 8)
461             .WithTag("TSTART", 16, 3)
462             .WithReservedBits(19, 1)
463             .WithTag("TSTOP", 20, 3)
464             .WithReservedBits(23, 1)
465             .WithTaggedFlag("RESTARTEN", 24)
466             .WithReservedBits(25, 7);
467 
GenerateTestRegister()468         protected DoubleWordRegister GenerateTestRegister() => new DoubleWordRegister(this)
469             .WithTaggedFlag("GPIODELAYSTABLE", 0)
470             .WithTaggedFlag("GPIODELAYXOR", 1)
471             .WithReservedBits(2, 30);
472 
GenerateInterruptFlagRegister()473         protected DoubleWordRegister GenerateInterruptFlagRegister() => interruptsManager.GetMaskedInterruptFlagRegister<DoubleWordRegister>();
474 
GenerateInterruptEnableRegister()475         protected DoubleWordRegister GenerateInterruptEnableRegister() => interruptsManager.GetInterruptEnableRegister<DoubleWordRegister>();
476 
GenerateInterruptFlagSetRegister()477         protected DoubleWordRegister GenerateInterruptFlagSetRegister() => interruptsManager.GetInterruptSetRegister<DoubleWordRegister>();
478 
GenerateInterruptFlagClearRegister()479         protected DoubleWordRegister GenerateInterruptFlagClearRegister() => interruptsManager.GetInterruptClearRegister<DoubleWordRegister>();
480 
HandleTxBufferData(byte data)481         private void HandleTxBufferData(byte data)
482         {
483             if(!transmitterEnableFlag.Value)
484             {
485                 this.Log(LogLevel.Warning, "Trying to send data, but the transmitter is disabled: 0x{0:X}", data);
486                 return;
487             }
488 
489             transferCompleteFlag.Value = false;
490             if(operationModeField.Value == OperationMode.Synchronous)
491             {
492                 if(spiSlaveDevice != null)
493                 {
494                     var result = spiSlaveDevice.Transmit(data);
495                     WriteChar(result);
496                 }
497                 else
498                 {
499                     this.Log(LogLevel.Warning, "Writing data in synchronous mode, but no device is currently connected.");
500                     WriteChar(0x0);
501                 }
502             }
503             else
504             {
505                 interruptsManager.SetInterrupt(Interrupt.TransmitBufferLevel);
506                 TransmitCharacter(data);
507                 interruptsManager.SetInterrupt(Interrupt.TransmitComplete);
508             }
509             transferCompleteFlag.Value = true;
510         }
511 
ReadBuffer()512         private byte ReadBuffer()
513         {
514             byte character;
515             return TryGetCharacter(out character) ? character : (byte)0;
516         }
517 
518         private readonly InterruptManager<Interrupt> interruptsManager;
519         private IEnumRegisterField<OversamplingMode> oversamplingField;
520         private IEnumRegisterField<OperationMode> operationModeField;
521         private IEnumRegisterField<Parity> parityBitModeField;
522         private IEnumRegisterField<Bits> stopBitsModeField;
523         private IValueRegisterField fractionalClockDividerField;
524         private IFlagRegisterField transferCompleteFlag;
525         private IFlagRegisterField receiveDataValidFlag;
526         private IFlagRegisterField receiverEnableFlag;
527         private IFlagRegisterField transmitterEnableFlag;
528         private readonly uint uartClockFrequency;
529         private ISPIPeripheral spiSlaveDevice;
530         private BufferState bufferState;
531 
532         private const int BufferSize = 3; // with shift register
533 
534         private enum OperationMode
535         {
536             Asynchronous,
537             Synchronous
538         }
539 
540         private enum OversamplingMode
541         {
542             Times16,
543             Times8,
544             Times6,
545             Times4
546         }
547 
548         private enum Interrupt
549         {
550             [Subvector(0)]
551             TransmitComplete,
552             [Subvector(0), NotSettable]
553             TransmitBufferLevel,
554             [Subvector(1), NotSettable]
555             ReceiveDataValid,
556             [Subvector(1)]
557             ReceiveBufferFull,
558             [Subvector(1)]
559             ReceiveOverflow,
560             [Subvector(1)]
561             ReceiveUnderflow,
562             [Subvector(0)]
563             TransmitOverflow,
564             [Subvector(0)]
565             TransmitUnderflow,
566             [Subvector(1)]
567             ParityError,
568             [Subvector(1)]
569             FramingError,
570             [Subvector(1)]
571             MultiProcessorAddressFrame,
572             [Subvector(1)]
573             SlaveSelectInMasterMode,
574             [Subvector(0)]
575             CollisionCheckFail,
576             [Subvector(0)]
577             TransmitIdle,
578             [Subvector(1)]
579             TimerComparator0,
580             [Subvector(1)]
581             TimerComparator1,
582             [Subvector(1)]
583             TimerComparator2
584         }
585     }
586 }