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