1 // 2 // Copyright (c) 2010-2024 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.Linq; 9 using System.Collections.Generic; 10 using System.Collections.ObjectModel; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Core; 15 using Antmicro.Renode.Time; 16 using Antmicro.Renode.Utilities; 17 using Antmicro.Renode.Utilities.Collections; 18 19 using TimeDirection = Antmicro.Renode.Time.Direction; 20 21 namespace Antmicro.Renode.Peripherals.Timers 22 { 23 public class RenesasRA_GPT : IDoubleWordPeripheral, INumberedGPIOOutput, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 24 { RenesasRA_GPT(IMachine machine, int numberOf32BitChannels, int numberOf16BitChannels, long commonRegistersOffset, long peripheralClockDFrequency)25 public RenesasRA_GPT(IMachine machine, int numberOf32BitChannels, int numberOf16BitChannels, long commonRegistersOffset, 26 long peripheralClockDFrequency) 27 { 28 this.peripheralClockDFrequency = peripheralClockDFrequency; 29 this.machine = machine; 30 31 this.numberOf32BitChannels = numberOf32BitChannels; 32 this.numberOf16BitChannels = numberOf16BitChannels; 33 this.channels = new GPTChannel[TotalChannels]; 34 35 Size = commonRegistersOffset + 0x100; 36 RegistersCollection = new DoubleWordRegisterCollection(this, BuildRegisterMap(commonRegistersOffset)); 37 38 Connections = new ReadOnlyDictionary<int, IGPIO>( 39 channels 40 .SelectMany(channel => channel.IRQ) 41 .Select((x, i) => new { Key = i, Value = (IGPIO)x }) 42 .ToDictionary(x => x.Key, x => x.Value) 43 ); 44 45 Reset(); 46 } 47 Reset()48 public void Reset() 49 { 50 RegistersCollection.Reset(); 51 } 52 ReadDoubleWord(long offset)53 public uint ReadDoubleWord(long offset) 54 { 55 return RegistersCollection.Read(offset); 56 } 57 WriteDoubleWord(long offset, uint value)58 public void WriteDoubleWord(long offset, uint value) 59 { 60 RegistersCollection.Write(offset, value); 61 } 62 63 public long Size { get; } 64 public DoubleWordRegisterCollection RegistersCollection { get; } 65 66 // IRQs are bundled in 9 signals per channel in the following order: 67 // 0: CCMPA - ompare match / input capture A 68 // 1: CCMPB - compare match / input capture B 69 // 2: CMPC - compare match C 70 // 3: CMPD - compare match D 71 // 4: CMPE - compare match E 72 // 5: CMPF - compare match F 73 // 6: OVF - overflow 74 // 7: UDF - underflow 75 // 8: PC - count stop 76 public IReadOnlyDictionary<int, IGPIO> Connections { get; } 77 BuildRegisterMap(long commonRegistersOffset)78 private Dictionary<long, DoubleWordRegister> BuildRegisterMap(long commonRegistersOffset) 79 { 80 var registerMap = new Dictionary<long, DoubleWordRegister> 81 { 82 {commonRegistersOffset + (long)CommonRegisters.OutputPhaseSwitchingControl, new DoubleWordRegister(this) 83 .WithFlag(0, name: "UF (Input Phase Soft Setting)") 84 .WithFlag(1, name: "VF (Input Phase Soft Setting)") 85 .WithFlag(2, name: "WF (Input Phase Soft Setting)") 86 .WithReservedBits(3, 1) 87 .WithFlag(4, name: "U (Input U-Phase Monitor)") 88 .WithFlag(5, name: "V (Input V-Phase Monitor)") 89 .WithFlag(6, name: "W (Input W-Phase Monitor)") 90 .WithReservedBits(7, 1) 91 .WithFlag(8, name: "EN (Output Phase Enable)") 92 .WithReservedBits(9, 7) 93 .WithFlag(16, name: "FB (External Feedback Signal Enable)") 94 .WithFlag(17, name: "P (Positive-Phase Output (P) Control)") 95 .WithFlag(18, name: "N (Negative-Phase Output (N) Control)") 96 .WithFlag(19, name: "INV (Output Phase Invert Control)") 97 .WithFlag(20, name: "RV (Output Phase Rotation Direction Reversal Control)") 98 .WithFlag(21, name: "ALIGN (Input Phase Alignment)") 99 .WithReservedBits(22, 2) 100 .WithValueField(24, 2, name: "GRP (Output Disabled Source Selection)") 101 .WithFlag(26, name: "GODF (Group Output Disable Function)") 102 .WithReservedBits(27, 2) 103 .WithFlag(29, name: "NFEN (External Input Noise Filter Enable)") 104 .WithValueField(30, 2, name: "NFCS (External Input Noise Filter Clock Selection)") 105 }, 106 }; 107 108 for(long i = 0; i < numberOf32BitChannels; ++i) 109 { 110 var channel = new GPTChannel(this, i, 32); 111 channels[i] = channel; 112 registerMap = registerMap 113 .Concat(BuildChannelRegisterMap(0x100 * i, channel)) 114 .ToDictionary(x => x.Key, x => x.Value); 115 } 116 117 for(long i = 0; i < numberOf16BitChannels; ++i) 118 { 119 // 16-bit channels are numbered after 32-bit channels, 120 // i.e. if 32-bit channels are 0 to 7 then 16-bit are 8 to 13. 121 var channelNumber = numberOf32BitChannels + i; 122 var channel = new GPTChannel(this, channelNumber, 16); 123 channels[channelNumber] = channel; 124 registerMap = registerMap 125 .Concat(BuildChannelRegisterMap(0x100 * channelNumber, channel)) 126 .ToDictionary(x => x.Key, x => x.Value); 127 } 128 129 return registerMap; 130 } 131 BuildChannelRegisterMap(long channelOffset, GPTChannel channel)132 private Dictionary<long, DoubleWordRegister> BuildChannelRegisterMap(long channelOffset, GPTChannel channel) 133 { 134 var registerMap = new Dictionary<long, DoubleWordRegister> 135 { 136 {channelOffset + (long)ChannelRegisters.WriteProtection, new DoubleWordRegister(this) 137 .WithFlag(0, name: "WP (Register Write Disable)") 138 .WithFlag(1, name: "STRWP (CSTRT Bit Write Disable)") 139 .WithFlag(2, name: "STPWP (CSTOP Bit Write Disable)") 140 .WithFlag(3, name: "CLRWP (CCLR Bit Write Disable)") 141 .WithFlag(4, name: "CMNWP (Common Register Write Disable)") 142 .WithReservedBits(5, 3) 143 .WithValueField(8, 8, name: "PRKEY (GTWP Key Code)") 144 .WithReservedBits(16, 16) 145 }, 146 {channelOffset + (long)ChannelRegisters.SoftwareStart, new DoubleWordRegister(this) 147 .WithFlags(0, TotalChannels, name: "CSTRT", 148 valueProviderCallback: (i, _) => channels[i].Enable, 149 writeCallback: (i, _, value) => 150 { 151 if(value) 152 { 153 channels[i].Enable = true; 154 } 155 } 156 ) 157 .WithReservedBits(TotalChannels, 32 - TotalChannels) 158 }, 159 {channelOffset + (long)ChannelRegisters.SoftwareStop, new DoubleWordRegister(this) 160 .WithFlags(0, TotalChannels, name: "CSTOP", 161 valueProviderCallback: (i, _) => !channels[i].Enable, 162 writeCallback: (i, _, value) => 163 { 164 if(value) 165 { 166 channels[i].Enable = false; 167 } 168 } 169 ) 170 .WithReservedBits(TotalChannels, 32 - TotalChannels) 171 }, 172 {channelOffset + (long)ChannelRegisters.SoftwareClear, new DoubleWordRegister(this) 173 .WithFlags(0, 14, name: "CCLR") 174 .WithReservedBits(14, 18) 175 }, 176 {channelOffset + (long)ChannelRegisters.StartSourceSelect, DefineSourceSelectRegister("Start", 'S')}, 177 {channelOffset + (long)ChannelRegisters.StopSourceSelect, DefineSourceSelectRegister("Stop", 'P')}, 178 {channelOffset + (long)ChannelRegisters.ClearSourceSelect, DefineSourceSelectRegister("Clear", 'C')}, 179 {channelOffset + (long)ChannelRegisters.UpCountSourceSelect, DefineSourceSelectRegister("Count Up", 'U', false)}, 180 {channelOffset + (long)ChannelRegisters.DownCountSourceSelect, DefineSourceSelectRegister("Count Down", 'D', false)}, 181 {channelOffset + (long)ChannelRegisters.InputCaptureSourceSelectA, DefineSourceSelectRegister("Input Capture", 'A', false, "GTCCRA")}, 182 {channelOffset + (long)ChannelRegisters.InputCaptureSourceSelectB, DefineSourceSelectRegister("Input Capture", 'B', false, "GTCCRB")}, 183 {channelOffset + (long)ChannelRegisters.TimerControl, new DoubleWordRegister(this) 184 .WithFlag(0, name: "CST (Count Start)") 185 .WithReservedBits(1, 15) 186 .WithEnumField<DoubleWordRegister, Mode>(16, 3, name: "MD (Mode Select)", 187 valueProviderCallback: _ => channel.Mode, 188 writeCallback: (_, value) => channel.Mode = value 189 ) 190 .WithReservedBits(19, 4) 191 .WithValueField(23, 4, name: "TPCS (Timer Prescaler Select)") 192 .WithReservedBits(27, 5) 193 }, 194 {channelOffset + (long)ChannelRegisters.CountDirectionAndDutySetting, new DoubleWordRegister(this) 195 .WithEnumField<DoubleWordRegister, Direction>(0, 1, name: "UD (Count Direction Setting)", 196 valueProviderCallback: _ => channel.Direction, 197 writeCallback: (_, value) => channel.Direction = value 198 ) 199 .WithFlag(1, name: "UDF (Forcible Count Direction Setting)") 200 .WithReservedBits(2, 14) 201 .WithValueField(16, 2, name: "OADTY (GTIOCnA Output Duty Setting)") 202 .WithFlag(18, name: "OADTYF (Forcible GTIOCnA Output Duty Setting)") 203 .WithFlag(19, name: "OADTYR (GTIOCnA Output Value Selecting)") 204 .WithReservedBits(20, 4) 205 .WithValueField(24, 2, name: "OBDTY (GTIOCnB Output Duty Setting)") 206 .WithFlag(26, name: "OBDTYF (Forcible GTIOCnB Output Duty Setting)") 207 .WithFlag(27, name: "OBDTYR (GTIOCnB Output Value Selecting)") 208 .WithReservedBits(28, 4) 209 }, 210 {channelOffset + (long)ChannelRegisters.IOControl, new DoubleWordRegister(this) 211 .WithValueField(0, 5, name: "GTIOA (GTIOCnA Pin Function Select)") 212 .WithReservedBits(5, 1) 213 .WithFlag(6, name: "OADFLT (GTIOCnA Pin Output Value Setting at the Count Stop)") 214 .WithFlag(7, name: "OAHLD (GTIOCnA Pin Output Value Setting at the Start/Stop Count)") 215 .WithFlag(8, name: "OAE (GTIOCnA Pin Output Enable)") 216 .WithFlag(9, name: "OADF (GTIOCnA Pin Disaable Value Setting)") 217 .WithReservedBits(11, 2) 218 .WithFlag(13, name: "NFAEN (Noise Filter A Enable)") 219 .WithValueField(14, 2, name: "NFCSA (Noise Filter A Sampling Clock Select)") 220 .WithValueField(16, 5, name: "GTIOB (GTIOCnB Pin Function Select)") 221 .WithReservedBits(21, 1) 222 .WithFlag(22, name: "OBDFLT (GTIOCnB Pin Output Value Setting at the Count Stop)") 223 .WithFlag(23, name: "OBHLD (GTIOCnB Pin Output Value Setting at the Start/Stop Count)") 224 .WithFlag(24, name: "OBE (GTIOCnB Pin Output Enable)") 225 .WithFlag(25, name: "OBDF (GTIOCnB Pin Disaable Value Setting)") 226 .WithReservedBits(27, 2) 227 .WithFlag(29, name: "NFBEN (Noise Filter B Enable)") 228 .WithValueField(30, 2, name: "NFCSB (Noise Filter B Sampling Clock Select)") 229 }, 230 {channelOffset + (long)ChannelRegisters.InterruptOutputSetting, new DoubleWordRegister(this) 231 .WithReservedBits(0, 16) 232 .WithFlag(16, name: "ADTRAUEN (GTADTRA Register Compare Match (Up-Counting) A/D Conversion Start)") 233 .WithFlag(17, name: "ADTRADEN (GTADTRA Register Compare Match (Down-Counting) A/D Conversion Start)") 234 .WithFlag(18, name: "ADTRBUEN (GTADTRB Register Compare Match (Up-Counting) A/D Conversion Start)") 235 .WithFlag(19, name: "ADTRBDEN (GTADTRB Register Compare Match (Down-Counting) A/D Conversion Start)") 236 .WithReservedBits(20, 4) 237 .WithValueField(24, 2, name: "GRP (Output Disable Source Select)") 238 .WithReservedBits(26, 3) 239 .WithFlag(29, name: "GRPABH (Same Time Output Level High Disable Request Enable)") 240 .WithFlag(30, name: "GRPABL (Same Time Output Level Low Disable Request Enable)") 241 .WithReservedBits(31, 1) 242 }, 243 // Status register defined later 244 {channelOffset + (long)ChannelRegisters.BufferEnable, new DoubleWordRegister(this) 245 .WithFlag(0, name: "BD0 (GTCCR Buffer Operation Disable)") 246 .WithFlag(1, name: "BD1 (GTPR Buffer Operation Disable)") 247 .WithFlag(2, name: "BD2 (GTAADTRA/GTADTRB Registers Buffer Operation Disable)") 248 .WithReservedBits(3, 13) 249 .WithValueField(16, 2, name: "CCRA (GTCCRA Buffer Operation)") 250 .WithValueField(18, 2, name: "CCRB (GTCCRB Buffer Operation)") 251 .WithValueField(20, 2, name: "PR (GTPR Buffer Operation)") 252 .WithFlag(22, name: "CCRSWT (GTCCRA and GTCCRB Forcible Buffer Operation)") 253 .WithReservedBits(23, 1) 254 .WithValueField(24, 2, name: "ADTTA (GTADTRA Register Buffer Transfer Timing Select)") 255 .WithFlag(26, name: "ADTDA (GTADTRA Register Double Buffer Operation)") 256 .WithReservedBits(27, 1) 257 .WithValueField(28, 2, name: "ADTTB (GTADTRB Register Buffer Transfer Timing Select)") 258 .WithFlag(30, name: "ADTDB (GTADTRB Register Double Buffer Operation)") 259 .WithReservedBits(31, 1) 260 }, 261 {channelOffset + (long)ChannelRegisters.Counter, new DoubleWordRegister(this) 262 .WithValueField(0, 32, name: "GTCNT", 263 valueProviderCallback: _ => channel.Value, 264 writeCallback: (_, value) => channel.Value = value 265 ) 266 }, 267 // Compare Capture register A..F defined later 268 {channelOffset + (long)ChannelRegisters.CycleSetting, new DoubleWordRegister(this) 269 .WithValueField(0, 32, name: "GTPR", 270 valueProviderCallback: _ => channel.Cycle, 271 writeCallback: (_, value) => channel.Cycle = value 272 ) 273 }, 274 {channelOffset + (long)ChannelRegisters.CycleSettingBuffer, new DoubleWordRegister(this) 275 .WithValueField(0, 32, name: "GTPBR") 276 }, 277 {channelOffset + (long)ChannelRegisters.ADConversionStartA, new DoubleWordRegister(this) 278 .WithValueField(0, 32, name: "GTADTRA") 279 }, 280 {channelOffset + (long)ChannelRegisters.ADConversionStartB, new DoubleWordRegister(this) 281 .WithValueField(0, 32, name: "GTADTRB") 282 }, 283 {channelOffset + (long)ChannelRegisters.ADConversionStartBufferA, new DoubleWordRegister(this) 284 .WithValueField(0, 32, name: "GTADTBRA") 285 }, 286 {channelOffset + (long)ChannelRegisters.ADConversionStartBufferB, new DoubleWordRegister(this) 287 .WithValueField(0, 32, name: "GTADTBRB") 288 }, 289 {channelOffset + (long)ChannelRegisters.ADConversionStartDoubleBufferA, new DoubleWordRegister(this) 290 .WithValueField(0, 32, name: "GTADTDBRA") 291 }, 292 {channelOffset + (long)ChannelRegisters.ADConversionStartDoubleBufferB, new DoubleWordRegister(this) 293 .WithValueField(0, 32, name: "GTADTDBRB") 294 }, 295 {channelOffset + (long)ChannelRegisters.DeadTimeControl, new DoubleWordRegister(this) 296 .WithFlag(0, name: "TDE (Negative-Phase Waveform Setting)") 297 .WithReservedBits(1, 31) 298 }, 299 {channelOffset + (long)ChannelRegisters.DeadTimeValue, new DoubleWordRegister(this) 300 .WithValueField(0, 32, name: "GTDVU") 301 }, 302 {channelOffset + (long)ChannelRegisters.ADConversionStartSignalMonitoring, new DoubleWordRegister(this) 303 .WithValueField(0, 2, name: "ADSMS0 (A/D Conversion Start Request Signal Monitor 0 Selection)") 304 .WithReservedBits(2, 6) 305 .WithFlag(8, name: "ADSMEN0 (A/D Conversion Start Request Signal Monitor 0 Output Enabling)") 306 .WithReservedBits(9, 7) 307 .WithValueField(16, 2, name: "ADSMS1 (A/D Conversion Start Request Signal Monitor 1 Selection)") 308 .WithReservedBits(18, 6) 309 .WithFlag(24, name: "ADSMEN1 (A/D Conversion Start Request Signal Monitor 1 Output Enabling)") 310 .WithReservedBits(25, 7) 311 }, 312 {channelOffset + (long)ChannelRegisters.InterChannelSetting, new DoubleWordRegister(this) 313 .WithValueField(0, 3, name: "ICLFA (GTIOCnA Output Logical Operation Function Select)") 314 .WithReservedBits(3, 1) 315 .WithValueField(4, 6, name: "ICLFSELC (Inter Channel Signaal C Select)") 316 .WithReservedBits(10, 6) 317 .WithValueField(16, 3, name: "ICLFB (GTIOCnB Output Logical Operation Function Select)") 318 .WithReservedBits(19, 1) 319 .WithValueField(20, 6, name: "ICLFSELD (Inter Channel Signal D Select)") 320 .WithReservedBits(26, 6) 321 }, 322 {channelOffset + (long)ChannelRegisters.PeriodCount, new DoubleWordRegister(this) 323 .WithFlag(0, name: "PCEN (Period Count Function Enable)") 324 .WithReservedBits(1, 7) 325 .WithFlag(8, name: "ASTP (Automatic Stop Function Enable)") 326 .WithReservedBits(9, 7) 327 .WithValueField(16, 12, name: "PCNT (Period Counter)") 328 .WithReservedBits(28, 4) 329 }, 330 {channelOffset + (long)ChannelRegisters.OperationEnableBitChannelSelect, new DoubleWordRegister(this) 331 .WithFlags(0, 14, name: "SECSEL") 332 .WithReservedBits(14, 18) 333 }, 334 {channelOffset + (long)ChannelRegisters.OperationEnableBit, new DoubleWordRegister(this) 335 .WithFlag(0, name: "SBDCE (GTCCR Register Buffer Operation Simultaneous Enable)") 336 .WithFlag(1, name: "SBDPE (GTPR Register Buffer Operation Simultaneous Enable)") 337 .WithFlag(2, name: "SBDAE (GTADTR Register Buffer Operation Simultaneous Enable)") 338 .WithReservedBits(3, 5) 339 .WithFlag(8, name: "SBDCD (GTCCR Register Buffer Operation Simultaneous Disable)") 340 .WithFlag(9, name: "SBDPD (GTPR Register Buffer Operation Simultaneous Disable)") 341 .WithFlag(10, name: "SBDAD (GTADTR Register Buffer Operation Simultaneous Disable)") 342 .WithReservedBits(17, 7) 343 .WithReservedBits(25, 7) 344 }, 345 }; 346 347 var statusRegister = new DoubleWordRegister(this); 348 foreach(var f in RangeWithLetters(0, 6)) 349 { 350 statusRegister 351 .WithFlag(f.offset, name: $"TCF{f.c} (Input Capture/Compare Match Flag {f.c})"); 352 } 353 statusRegister 354 .WithFlag(6, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TCFPO (Overflow Flag)", 355 valueProviderCallback: _ => channel.Overflow, 356 writeCallback: (_, __) => channel.Overflow = false 357 ) 358 .WithFlag(7, name: "TCFPU (Underflow Flag)") 359 .WithReservedBits(8, 7) 360 .WithFlag(15, name: "TUCF (Count Direction Flag)") 361 .WithFlag(16, name: "ADTRAUF (GTADTRA Register Compare Match (Up-Counting) A/D Conversion Start)") 362 .WithFlag(17, name: "ADTRADF (GTADTRA Register Compare Match (Down-Counting) A/D Conversion Start)") 363 .WithFlag(18, name: "ADTRBUF (GTADTRB Register Compare Match (Up-Counting) A/D Conversion Start)") 364 .WithFlag(19, name: "ADTRBDF (GTADTRB Register Compare Match (Down-Counting) A/D Conversion Start)") 365 .WithReservedBits(20, 4) 366 .WithFlag(24, name: "ODF (Output Disable Flag)") 367 .WithReservedBits(25, 4) 368 .WithFlag(29, name: "OABHF (Same Time Output Level High Flag)") 369 .WithFlag(30, name: "OABLF (Same Time Output Level Low Flag)") 370 .WithFlag(31, name: "PCF (Period Count Function Finish Flag)"); 371 registerMap.Add(channelOffset + (long)ChannelRegisters.Status, statusRegister); 372 373 foreach(var r in RangeWithLetters((int)channelOffset + (int)ChannelRegisters.CompareCaptureA, 6, 4)) 374 { 375 var compareCaptureRegister = new DoubleWordRegister(this) 376 .WithValueField(0, 32, name: $"GTCCR{r.c}"); 377 registerMap.Add(r.offset, compareCaptureRegister); 378 } 379 380 return registerMap; 381 } 382 DefineSourceSelectRegister(string name, char marker, bool hasClear = true, string sourceName = R)383 private DoubleWordRegister DefineSourceSelectRegister(string name, char marker, bool hasClear = true, string sourceName = "Counter") 384 { 385 var sourceSelectRegister = new DoubleWordRegister(this); 386 foreach(var f in RangeWithLetters(0, 4, 2)) 387 { 388 sourceSelectRegister 389 .WithFlag(f.offset, name: $"{marker}SGTRG{f.c}R (GTETRG{f.c} Pin Rising Input Source {sourceName} {name} Enable)") 390 .WithFlag(f.offset + 1, name: $"{marker}SGTRG{f.c}F (GTETRG{f.c} Pin Falling Input Source {sourceName} {name} Enable)"); 391 } 392 foreach(var f in RangeWithLetters(8, 2, 4)) 393 { 394 var other = f.c == 'A' ? 'B' : 'A'; 395 sourceSelectRegister 396 .WithFlag(f.offset, name: $"{marker}SC{f.c}RBL (GTIOCn{f.c} Pin Rising Input during GTIOCn{other} Value Low Source {sourceName} {name} Enable)") 397 .WithFlag(f.offset + 1, name: $"{marker}SC{f.c}RBH (GTIOCn{f.c} Pin Rising Input during GTIOCn{other} Value High Source {sourceName} {name} Enable)") 398 .WithFlag(f.offset + 2, name: $"{marker}SC{f.c}FBL (GTIOCn{f.c} Pin Falling Input during GTIOCn{other} Value Low Source {sourceName} {name} Enable)") 399 .WithFlag(f.offset + 3, name: $"{marker}SC{f.c}FBH (GTIOCn{f.c} Pin Falling Input during GTIOCn{other} Value High Source {sourceName} {name} Enable)"); 400 } 401 foreach(var f in RangeWithLetters(16, 8)) 402 { 403 sourceSelectRegister 404 .WithFlag(f.offset, name: $"{marker}SELC{f.c} (ELC_GPT{f.c} Event Source {sourceName} {name} Enable)"); 405 } 406 if(hasClear) 407 { 408 sourceSelectRegister 409 .WithReservedBits(24, 7) 410 .WithFlag(31, name: $"C{name.ToUpper()} (Software Source {sourceName} {name} Enable)"); 411 } 412 else 413 { 414 sourceSelectRegister 415 .WithReservedBits(24, 8); 416 } 417 return sourceSelectRegister; 418 } 419 420 private class OffsetWithLetter 421 { 422 public int index; 423 public int offset; 424 public char c; 425 OffsetWithLetter(int index, int offset, char c)426 public OffsetWithLetter(int index, int offset, char c) 427 { 428 this.index = index; 429 this.offset = offset; 430 this.c = c; 431 } 432 } 433 RangeWithLetters(int start, int count, int step = 1)434 private IEnumerable<OffsetWithLetter> RangeWithLetters(int start, int count, int step = 1) 435 { 436 for(int i = 0; i < count; ++i) 437 { 438 int offset = start + i * step; 439 var c = (char)('A' + i); 440 yield return new OffsetWithLetter(i, offset, c); 441 } 442 } 443 444 private int TotalChannels => numberOf32BitChannels + numberOf16BitChannels; 445 446 private readonly IMachine machine; 447 private readonly int numberOf32BitChannels; 448 private readonly int numberOf16BitChannels; 449 private readonly long peripheralClockDFrequency; 450 private readonly GPTChannel[] channels; 451 452 private class GPTChannel 453 { GPTChannel(RenesasRA_GPT parent, long index, int width)454 public GPTChannel(RenesasRA_GPT parent, long index, int width) 455 { 456 this.parent = parent; 457 this.index = index; 458 this.width = width; 459 IRQ = new GPIO[InterruptCount]; 460 for(int i = 0; i < InterruptCount; ++i) 461 { 462 IRQ[i] = new GPIO(); 463 } 464 465 timer = new LimitTimer(parent.machine.ClockSource, parent.peripheralClockDFrequency, parent, $"Timer{index}", 466 MaxLimit, direction: TimeDirection.Descending, workMode: WorkMode.Periodic, eventEnabled: true 467 ); 468 timer.LimitReached += OnMainTimerLimitReached; 469 470 Reset(); 471 } 472 Reset()473 public void Reset() 474 { 475 Overflow = false; 476 timer.Reset(); 477 Cycle = MaxLimit; 478 Direction = Direction.DownCounting; 479 Mode = Mode.SawWave; 480 } 481 482 public Mode Mode 483 { 484 get => mode; 485 set 486 { 487 if(value != Mode.SawWave) 488 { 489 this.parent.Log(LogLevel.Warning, "GPT{0}: Modes other than Saw Wave (default) are not supported yet. Ignoring", index); 490 return; 491 } 492 mode = value; 493 } 494 } 495 496 public Direction Direction 497 { 498 get => direction; 499 set 500 { 501 direction = value; 502 timer.Direction = direction == Direction.UpCounting ? TimeDirection.Ascending : TimeDirection.Descending; 503 } 504 } 505 506 public bool Enable 507 { 508 get => timer.Enabled; 509 set 510 { 511 timer.Enabled = value; 512 } 513 } 514 515 public ulong Cycle 516 { 517 get => timer.Limit; 518 set 519 { 520 if(value > MaxLimit) 521 { 522 this.parent.Log(LogLevel.Warning, "GPT{0}: Cycle {1} is higher than maximum limit of {2}. Truncating to {3} bits", index, value, MaxLimit, width); 523 } 524 timer.Limit = value & MaxLimit; 525 } 526 } 527 528 public ulong Value 529 { 530 get => timer.Value; 531 set 532 { 533 if(Enable) 534 { 535 this.parent.Log(LogLevel.Warning, "GPT{0}: Setting GTCNT while counting is still on-going. Ignoring", index); 536 return; 537 } 538 if(value > MaxLimit) 539 { 540 this.parent.Log(LogLevel.Warning, "GPT{0}: Value {1} is higher than maximum limit of {2}. Truncating to {3} bits", index, value, MaxLimit, width); 541 } 542 var newValue = value & MaxLimit; 543 if(newValue >= Cycle) 544 { 545 Overflow = true; 546 IRQ[OvfInterruptIndex].Blink(); 547 timer.Reset(); 548 } 549 else 550 { 551 Overflow = false; 552 timer.Value = newValue; 553 } 554 } 555 } 556 557 public GPIO[] IRQ { get; } 558 559 public bool Overflow { get; set; } 560 public bool Underflow { get; set; } 561 562 public const long InterruptCount = 9; 563 OnMainTimerLimitReached()564 private void OnMainTimerLimitReached() 565 { 566 if(direction == Direction.UpCounting) 567 { 568 Overflow = true; 569 IRQ[OvfInterruptIndex].Blink(); 570 } 571 else 572 { 573 Underflow = true; 574 IRQ[UdfInterruptIndex].Blink(); 575 } 576 } 577 578 private ulong MaxLimit => (1ul << width) - 1ul; 579 580 private Mode mode; 581 private Direction direction; 582 583 private readonly LimitTimer timer; 584 private readonly RenesasRA_GPT parent; 585 private readonly long index; 586 private readonly int width; 587 588 private const long OvfInterruptIndex = 6; 589 private const long UdfInterruptIndex = 7; 590 } 591 592 public enum Mode 593 { 594 // single buffer or double buffer possible 595 SawWave = 0b000, 596 // fixed buffer operation 597 SawWaveOneShot = 0b001, 598 // single buffer or double buffer possible 599 // 32-bit transfer at trough 600 TriangleWave1 = 0b100, 601 // single buffer or double buffer possible 602 // 32-bit transfer at crest and trough 603 TriangleWave2 = 0b101, 604 // fixed buffer operation 605 // 64-bit transfer at trough 606 TriangleWave3 = 0b110, 607 } 608 609 public enum Direction 610 { 611 DownCounting = 0, 612 UpCounting = 1, 613 } 614 615 public enum ChannelRegisters 616 { 617 WriteProtection = 0x00, 618 SoftwareStart = 0x04, 619 SoftwareStop = 0x08, 620 SoftwareClear = 0x0C, 621 StartSourceSelect = 0x10, 622 StopSourceSelect = 0x14, 623 ClearSourceSelect = 0x18, 624 UpCountSourceSelect = 0x1C, 625 DownCountSourceSelect = 0x20, 626 InputCaptureSourceSelectA = 0x24, 627 InputCaptureSourceSelectB = 0x28, 628 TimerControl = 0x2C, 629 CountDirectionAndDutySetting = 0x30, 630 IOControl = 0x34, 631 InterruptOutputSetting = 0x38, 632 Status = 0x3C, 633 BufferEnable = 0x40, 634 Counter = 0x48, 635 CompareCaptureA = 0x4C, 636 // CompareCaptureB..F = 0x50..0x60, 637 CycleSetting = 0x64, 638 CycleSettingBuffer = 0x68, 639 ADConversionStartA = 0x70, 640 ADConversionStartB = 0x7C, 641 ADConversionStartBufferA = 0x74, 642 ADConversionStartBufferB = 0x80, 643 ADConversionStartDoubleBufferA = 0x78, 644 ADConversionStartDoubleBufferB = 0x84, 645 DeadTimeControl = 0x88, 646 DeadTimeValue = 0x8C, 647 ADConversionStartSignalMonitoring = 0xA4, 648 InterChannelSetting = 0xB8, 649 PeriodCount = 0xBC, 650 OperationEnableBitChannelSelect = 0xD0, 651 OperationEnableBit = 0xD4, 652 } 653 654 public enum CommonRegisters 655 { 656 OutputPhaseSwitchingControl = 0x00, 657 } 658 } 659 } 660