1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using System;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Peripherals.Bus;
12 using System.Collections.Generic;
13 using Antmicro.Migrant;
14 
15 namespace Antmicro.Renode.Peripherals.UART
16 {
17     public class STM32W_UART :  IDoubleWordPeripheral, IUART
18     {
STM32W_UART()19         public STM32W_UART()
20         {
21             IRQ = new GPIO();
22             charFifo = new Queue<byte>();
23         }
24 
25         [field: Transient]
26         public event Action<byte> CharReceived;
27 
28         public GPIO IRQ { get; private set; }
29 
WriteChar(byte value)30         public void WriteChar(byte value)
31         {
32             lock(charFifo)
33             {
34                 charFifo.Enqueue(value);
35                 Update();
36             }
37         }
38 
39         [ConnectionRegion("irq")]
WriteDoubleWordIRQ(long address, uint value)40         public void WriteDoubleWordIRQ(long address, uint value)
41         {
42 
43         }
44 
WriteDoubleWord(long address, uint value)45         public void WriteDoubleWord(long address, uint value)
46         {
47             if(address == 0x3C)
48             {
49                 var handler = CharReceived;
50                 if(handler != null)
51                 {
52                     handler((byte)(value & 0xFF));
53                 }
54                 return;
55                 // data register
56             }
57 
58             switch((Register)address)
59             {
60             case Register.Control:
61                 controlRegister = value;
62                 break;
63             case Register.BaudRate1:
64                 baudRate1 = value;
65                 break;
66             case Register.BaudRate2:
67                 baudRate2 = value;
68                 break;
69             }
70         }
71 
72         [ConnectionRegion("irq")]
ReadDoubleWordIRQ(long offset)73         public uint ReadDoubleWordIRQ(long offset)
74         {
75             if(offset == 0)
76             {
77                 uint res = (1 << 1);
78                 if(charFifo.Count > 0)
79                     res |= 1;
80                 return res;
81             }
82             return 0;
83         }
84 
ReadDoubleWord(long offset)85         public uint ReadDoubleWord(long offset)
86         {
87             switch(offset)
88             {
89             case 0x3c:
90                 var returnValue = charFifo.Dequeue();
91                 Update();
92                 if(returnValue == 0x0D)
93                     return 0x0A;
94                 return returnValue;
95             default:
96                 return 0;
97             }
98         }
99 
Reset()100         public void Reset()
101         {
102             // TODO!
103         }
104 
Update()105         private void Update()
106         {
107             IRQ.Set(/*txInterruptEnabled ||*/ charFifo.Count > 0);
108         }
109 
110         private uint controlRegister;
111         private uint baudRate1;
112         private uint baudRate2;
113         private readonly Queue<byte> charFifo;
114 
115         [Flags]
116         private enum Control : uint
117         {
118             Stop            = 1 << 2,
119             ParityEnabled   = 1 << 3,
120             ParitySelection = 1 << 4
121         }
122 
123         private enum Register : long
124         {
125             // TODO: I don't know if the offset should be 0xC85C or Ox5C - check it!
126             Control    = 0xC85C, // SC1_UARTCR
127             BaudRate1  = 0xC868, // SC1_UARTBRR1
128             BaudRate2  = 0xC86C  // SC1_UARTBRR2
129         }
130 
131         public Bits StopBits
132         {
133             get
134             {
135                 return (controlRegister & (uint)Control.Stop) == 0 ? Bits.One : Bits.Two;
136             }
137         }
138 
139         public Parity ParityBit
140         {
141             get
142             {
143                 if ((controlRegister & (uint)Control.ParityEnabled) == 0)
144                 {
145                     return Parity.None;
146                 }
147                 else
148                 {
149                     return (controlRegister & (uint)Control.ParitySelection) == 0 ? Parity.Even : Parity.Odd;
150                 }
151             }
152         }
153 
154         public uint BaudRate
155         {
156             get
157             {
158                 var divisor = ((2 * (baudRate1 & 0xFFFF) + (baudRate2 & 0x1)));
159                 return divisor == 0 ? 0 : UARTClockFrequency / divisor;
160             }
161         }
162 
163         private const uint UARTClockFrequency = 24000000; // 24Mhz
164     }
165 }
166 
167