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.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 
14 namespace Antmicro.Renode.Peripherals.UART
15 {
16     public class Murax_UART : UARTBase, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
17     {
Murax_UART(IMachine machine)18         public Murax_UART(IMachine machine) : base(machine)
19         {
20             RegistersCollection = new DoubleWordRegisterCollection(this);
21             DefineRegisters();
22         }
23 
ReadDoubleWord(long offset)24         public uint ReadDoubleWord(long offset)
25         {
26             return RegistersCollection.Read(offset);
27         }
28 
WriteDoubleWord(long offset, uint value)29         public void WriteDoubleWord(long offset, uint value)
30         {
31             RegistersCollection.Write(offset, value);
32         }
33 
Reset()34         public override void Reset()
35         {
36             base.Reset();
37             RegistersCollection.Reset();
38             UpdateInterrupts();
39         }
40 
41         public long Size => 0x10;
42 
43         public override Bits StopBits => stopBits;
44 
45         public override Parity ParityBit => parity;
46 
47         public override uint BaudRate => 0;
48 
49         public GPIO IRQ { get; } = new GPIO();
50 
51         public DoubleWordRegisterCollection RegistersCollection { get; private set; }
52 
CharWritten()53         protected override void CharWritten()
54         {
55             UpdateInterrupts();
56         }
57 
QueueEmptied()58         protected override void QueueEmptied()
59         {
60             UpdateInterrupts();
61         }
62 
DefineRegisters()63         private void DefineRegisters()
64         {
65             Registers.Data.Define(this)
66                 .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value),
67                     valueProviderCallback: _ => {
68                         if(!TryGetCharacter(out var character))
69                         {
70                             this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO.");
71                         }
72                         return character;
73                     })
74             ;
75 
76             Registers.Status.Define(this)
77                 .WithTag("txInterruptEnabled", 0, 1)
78                 .WithFlag(1, out rxInterruptEnabled)
79                 .WithReservedBits(2, 6)
80                 .WithTag("txInterruptActive", 8, 1)
81                 .WithFlag(9, FieldMode.Read, name: "rxInterruptActive", valueProviderCallback: _ => Count != 0)
82                 .WithReservedBits(10, 6)
83                 .WithTag("txFifoOccupancy", 16, 8)
84                 .WithTag("rxFifoOccupancy", 24, 8)
85                 .WithWriteCallback((_, __) => UpdateInterrupts())
86             ;
87 
88             Registers.FrameConfig.Define(this)
89                 .WithTag("frameDataLength", 0, 8)
90                 .WithEnumField<DoubleWordRegister, InnerParity>(8, 2, name: "parity",
91                     writeCallback: (_, val) =>
92                     {
93                         switch(val)
94                         {
95                         case InnerParity.None:
96                             parity = Parity.None;
97                             break;
98                         case InnerParity.Even:
99                             parity = Parity.Even;
100                             break;
101                         case InnerParity.Odd:
102                             parity = Parity.Odd;
103                             break;
104                         default:
105                             this.Log(LogLevel.Warning, "Unexpected parity value: {0}", val);
106                             break;
107                         }
108                     })
109                 .WithEnumField<DoubleWordRegister, InnerStopBits>(16, 1, name: "stopBits",
110                     writeCallback: (_, val) =>
111                     {
112                         switch(val)
113                         {
114                         case InnerStopBits.One:
115                             stopBits = Bits.One;
116                             break;
117                         case InnerStopBits.Two:
118                             stopBits = Bits.Two;
119                             break;
120                         }
121                     });
122             ;
123         }
124 
UpdateInterrupts()125         private void UpdateInterrupts()
126         {
127             var eventPending = (rxInterruptEnabled.Value && Count != 0);
128             this.Log(LogLevel.Info, "Setting interrupt to: {0}", eventPending);
129             IRQ.Set(eventPending);
130         }
131 
132         private IFlagRegisterField rxInterruptEnabled;
133         private Bits stopBits;
134         private Parity parity;
135 
136         private enum Registers
137         {
138             Data = 0x0,
139             Status = 0x4,
140             ClockDivider = 0x8,
141             FrameConfig = 0xC
142         }
143 
144         private enum InnerParity
145         {
146             None,
147             Even,
148             Odd
149         }
150 
151         private enum InnerStopBits
152         {
153             One,
154             Two
155         }
156     }
157 }
158