1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2022-2023 Sean Cross
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.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.I2C;
13 using Antmicro.Renode.Peripherals.Timers;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.Timers
17 {
18     public class ABRTCMC : II2CPeripheral, IProvidesRegisterCollection<ByteRegisterCollection>
19     {
ABRTCMC()20         public ABRTCMC()
21         {
22             RegistersCollection = new ByteRegisterCollection(this);
23 
24             Registers.Control0.Define(this)
25                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => false, name: "CAP")
26                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => false, name: "N")
27                 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => false, name: "STOP")
28                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "SR")
29                 .WithFlag(3, out twelveOrTwentyFourHourMode, name: "12_24")
30                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "SIE")
31                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => false, name: "AIE")
32                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "CIE")
33             ;
34 
35             Registers.Control1.Define(this)
36                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => false, name: "WTAF")
37                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => false, name: "CTAF")
38                 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => false, name: "CTBF")
39                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "SF")
40                 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => false, name: "AF")
41                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "WTAIE")
42                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => false, name: "CTAIE")
43                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "CTBIE")
44             ;
45 
46             Registers.Control2.Define(this)
47                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => false, name: "PM2")
48                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => false, name: "PM1")
49                 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => false, name: "PM0")
50                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "X")
51                 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => false, name: "BSF")
52                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "BLF")
53                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => false, name: "BSEI")
54                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "BLIE")
55             ;
56 
57             Registers.Seconds.Define(this)
58                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => false, name: "OS")
59                 .WithValueField(0, 7, FieldMode.Read, name: "SECONDS", valueProviderCallback: _ => IntToBcd(DateTime.Now.Second))
60             ;
61 
62             Registers.Minutes.Define(this)
63                 .WithReservedBits(7, 1)
64                 .WithValueField(0, 7, FieldMode.Read, name: "MINUTES", valueProviderCallback: _ => IntToBcd(DateTime.Now.Minute))
65             ;
66 
67             Registers.Hours.Define(this)
68                 .WithReservedBits(6, 2)
69                 .WithValueField(0, 6, FieldMode.Read, name: "HOURS", valueProviderCallback: _ => IntToBcd(DateTime.Now.Hour))
70             ;
71 
72             Registers.Days.Define(this)
73                 .WithReservedBits(6, 2)
74                 .WithValueField(0, 6, FieldMode.Read, name: "DAYS", valueProviderCallback: _ => IntToBcd(DateTime.Now.Day))
75             ;
76 
77             Registers.Weekdays.Define(this)
78                 .WithReservedBits(5, 1)
79                 .WithValueField(0, 5, FieldMode.Read, name: "WEEKDAYS", valueProviderCallback: _ => IntToBcd((int)DateTime.Now.DayOfWeek + 1))
80             ;
81 
82             Registers.Months.Define(this)
83                 .WithReservedBits(5, 3)
84                 .WithValueField(0, 5, FieldMode.Read, name: "MONTHS", valueProviderCallback: _ => IntToBcd(DateTime.Now.Month))
85             ;
86 
87             Registers.Years.Define(this)
88                 .WithReservedBits(7, 1)
89                 .WithValueField(0, 7, FieldMode.Read, name: "YEARS", valueProviderCallback: _ => IntToBcd(DateTime.Now.Year % 100))
90             ;
91 
92             Registers.TimerAClock.Define(this)
93                 .WithReservedBits(7, 1)
94                 .WithValueField(0, 7, name: "TIMERACLOCK")
95             ;
96 
97             Registers.TimerA.Define(this)
98                 .WithReservedBits(7, 1)
99                 .WithValueField(0, 7, name: "TIMERA")
100             ;
101 
102             Reset();
103         }
104 
Reset()105         public void Reset()
106         {
107             RegistersCollection.Reset();
108 
109             address = 0;
110             addressAutoIncrement = true;
111             isFirstByte = true;
112             isSecondByte = false;
113         }
114 
IntToBcd(int input)115         private uint IntToBcd(int input)
116         {
117             int bcd = 0;
118             for(int digit = 0; digit < 3; ++digit)
119             {
120                 int nibble = input % 10;
121                 bcd |= nibble << (digit * 4);
122                 input /= 10;
123             }
124             return (uint)bcd;
125         }
126 
FinishTransmission()127         public void FinishTransmission()
128         {
129             // this.Log(LogLevel.Debug, "In slave FinishTransmission()");
130             isFirstByte = true;
131             isSecondByte = false;
132         }
133 
Write(byte[] data)134         public void Write(byte[] data)
135         {
136             this.Log(LogLevel.Debug, "Written {0} bytes: {1}", data.Length, Misc.PrettyPrintCollectionHex(data));
137             foreach(var b in data)
138             {
139                 WriteByte(b);
140             }
141         }
142 
WriteByte(byte b)143         public void WriteByte(byte b)
144         {
145             if(isFirstByte)
146             {
147                 isFirstByte = false;
148                 isSecondByte = true;
149                 return;
150             }
151 
152             if(isSecondByte)
153             {
154                 isSecondByte = false;
155                 address = b;
156                 return;
157             }
158 
159             this.Log(LogLevel.Debug, "RTC writing byte 0x{0:x} to register {1} (0x{1:x})", b, address);
160             RegistersCollection.Write(address, b);
161             TryIncrementAddress();
162         }
163 
Read(int count = 1)164         public byte[] Read(int count = 1)
165         {
166             var result = RegistersCollection.Read(address);
167             this.Log(LogLevel.Debug, "Reading register {1} (0x{1:x}) from device: 0x{0:x}", result, (Registers)address);
168             TryIncrementAddress();
169 
170             return new byte[] { result };
171         }
172 
173         public ByteRegisterCollection RegistersCollection { get; }
174 
TryIncrementAddress()175         private void TryIncrementAddress()
176         {
177             if(!addressAutoIncrement)
178             {
179                 return;
180             }
181             address = (byte)((address + 1) % 0x14);
182         }
183 
184         private byte address;
185         private bool addressAutoIncrement;
186         private bool isFirstByte;
187         private bool isSecondByte;
188 
189         private readonly IFlagRegisterField twelveOrTwentyFourHourMode;
190 
191         private enum Registers
192         {
193             Control0 = 0x00,
194             Control1 = 0x01,
195             Control2 = 0x02,
196             Seconds = 0x03,
197             Minutes = 0x04,
198             Hours = 0x05,
199             Days = 0x06,
200             Weekdays = 0x07,
201             Months = 0x08,
202             Years = 0x09,
203             MinuteAlarm = 0x0A,
204             HourAlarm = 0x0B,
205             DayAlarm = 0x0C,
206             WeekdayAlarm = 0x0D,
207             FrequencyOffset = 0x0E,
208             TimerClockOut = 0x0F,
209             TimerAClock = 0x10,
210             TimerA = 0x11,
211             TimerBClock = 0x12,
212             TimerB = 0x13,
213         }
214     }
215 }
216