1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using Antmicro.Renode.Core; 8 using Antmicro.Renode.Core.Structure.Registers; 9 using Antmicro.Renode.Logging; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Peripherals.CPU; 12 using Antmicro.Renode.Peripherals.Memory; 13 14 namespace Antmicro.Renode.Peripherals.Miscellaneous 15 { 16 // XTAL32M registers are in the RenesasDA14_XTAL32MRegisters model. 17 [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] 18 public class RenesasDA14_ClockGenerationController : IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 19 { RenesasDA14_ClockGenerationController(IMachine machine, RenesasDA14_XTAL32MRegisters xtal32m, MappedMemory rom, MappedMemory eflashDataText)20 public RenesasDA14_ClockGenerationController(IMachine machine, RenesasDA14_XTAL32MRegisters xtal32m, MappedMemory rom, MappedMemory eflashDataText) 21 { 22 this.machine = machine; 23 this.xtal32m = xtal32m; 24 this.rom = rom; 25 this.eflashDataText = eflashDataText; 26 27 RegistersCollection = new DoubleWordRegisterCollection(this); 28 29 DefineRegisters(); 30 Reset(); 31 } 32 Reset()33 public void Reset() 34 { 35 RegistersCollection.Reset(); 36 } 37 ReadDoubleWord(long offset)38 public uint ReadDoubleWord(long offset) 39 { 40 return RegistersCollection.Read(offset); 41 } 42 WriteDoubleWord(long offset, uint value)43 public void WriteDoubleWord(long offset, uint value) 44 { 45 RegistersCollection.Write(offset, value); 46 } 47 48 public long Size => 0x100; 49 50 public DoubleWordRegisterCollection RegistersCollection { get; } 51 DefineRegisters()52 private void DefineRegisters() 53 { 54 Registers.ClockAMBA.Define(this, 0x12) 55 .WithValueField(0, 3, name: "HCLK_DIV") 56 .WithReservedBits(3, 1) 57 .WithValueField(4, 2, name: "PCLK_DIV") 58 .WithFlag(6, name: "AES_CLK_ENABLE") 59 .WithFlag(7, name: "QDEC_CLK_ENABLE") 60 .WithReservedBits(8, 2) 61 .WithValueField(10, 2, name: "QSPI_DIV") 62 .WithFlag(12, name: "QSPI_ENABLE") 63 .WithReservedBits(13, 19); 64 65 Registers.ResetControl.Define(this) 66 .WithFlag(0, name: "GATE_RST_WITH_FCU") 67 .WithFlag(1, name: "SYS_CACHE_FLUSH_WITH_SW_RESET") 68 .WithFlag(2, name: "CMAC_CACHE_FLUSH_WITH_SW_RESET") 69 .WithReservedBits(3, 29); 70 71 Registers.RadioPLL.Define(this, 0x4) 72 .WithFlag(0, name: "CMAC_CLK_ENABLE") 73 .WithFlag(1, name: "CMAC_CLK_SEL") 74 .WithFlag(2, name: "CMAC_SYNCH_RESET") 75 .WithFlag(3, name: "RFCU_ENABLE") 76 .WithReservedBits(4, 28); 77 78 Registers.ClockControl.Define(this, 0x2001) 79 .WithEnumField<DoubleWordRegister, SystemClock>(0, 2, out systemClock, name: "SYS_CLK_SEL") 80 .WithValueField(2, 2, name: "LP_CLK_SEL") 81 .WithReservedBits(4, 1) 82 .WithFlag(5, name: "XTAL32M_DISABLE") 83 .WithReservedBits(6, 6) 84 .WithFlag(12, FieldMode.Read, name: "RUNNING_AT_LP_CLOCK", valueProviderCallback: _ => systemClock.Value == SystemClock.RCLP) 85 .WithFlag(13, FieldMode.Read, name: "RUNNING_AT_RC32M", valueProviderCallback: _ => systemClock.Value == SystemClock.RC32M) 86 .WithFlag(14, FieldMode.Read, name: "RUNNING_AT_XTAL32M", valueProviderCallback: _ => systemClock.Value == SystemClock.XTAL32M) 87 .WithFlag(15, FieldMode.Read, name: "RUNNING_AT_DBLR64M", valueProviderCallback: _ => systemClock.Value == SystemClock.DBLR64M) 88 .WithReservedBits(16, 16); 89 90 Registers.Switch2XTAL.Define(this) 91 .WithFlag(0, FieldMode.WriteOneToClear, name: "SWITCH2XTAL", 92 writeCallback: (_, value) => 93 { 94 if(value && systemClock.Value == SystemClock.RC32M) 95 { 96 systemClock.Value = SystemClock.XTAL32M; 97 } 98 }) 99 .WithReservedBits(1, 31); 100 101 Registers.PMUClock.Define(this, 0x40F) 102 .WithFlag(0, out periphSleep, name: "PERIPH_SLEEP") 103 .WithFlag(1, out radioSleep, name: "RADIO_SLEEP") 104 .WithFlag(2, out timSleep, name: "TIM_SLEEP") 105 .WithFlag(3, out comSleep, name: "COM_SLEEP") 106 .WithFlag(4, name: "MAP_BANDGAP_EN") 107 .WithFlag(5, name: "RESET_ON_WAKEUP") 108 .WithFlag(6, out sysSleep, name: "SYS_SLEEP") 109 .WithFlag(7, name: "RETAIN_CACHE") 110 .WithReservedBits(8, 1) 111 .WithFlag(9, name: "LP_CLK_OUTPUT_EN") 112 .WithFlag(10, out audSleep, name: "AUD_SLEEP") 113 .WithFlag(11, name: "RETAIN_CMAC_CACHE") 114 .WithReservedBits(12, 20) 115 .WithWriteCallback((_, __) => 116 { 117 if(!timSleep.Value) 118 { 119 xtal32m.Enable = true; 120 } 121 }); 122 123 Registers.SystemControl.Define(this) 124 .WithEnumField<DoubleWordRegister, RemapAddress>(0, 3, out remapAddress, name: "REMAP_ADDR0") 125 .WithFlag(3, name: "REMAP_INTVECT") 126 .WithReservedBits(4, 3) 127 .WithFlag(7, name: "DEBUGGER_ENABLE") 128 .WithReservedBits(8, 2) 129 .WithFlag(10, name: "CACHERAM_MUX") 130 .WithReservedBits(11, 4) 131 .WithFlag(15, FieldMode.WriteOneToClear, name: "SW_RESET", 132 writeCallback: (_, value) => 133 { 134 if(!value) 135 { 136 return; 137 } 138 if(!machine.SystemBus.TryGetCurrentCPU(out var cpu)) 139 { 140 this.Log(LogLevel.Error, "Tried to initialize a software reset, but no CPU is detected. Ignoring this operation"); 141 return; 142 } 143 if(remapAddress.Value != RemapAddress.EFlash) 144 { 145 this.Log(LogLevel.Error, "Tried to initialize remapping of {0} to 0x0, but it is currently unsupported. Ignoring this operation", remapAddress.ToString()); 146 return; 147 } 148 // we need to cast to ICPUWithRegisters to access SetRegister 149 ICPUWithRegisters cpuWithRegisters = cpu as ICPUWithRegisters; 150 if(cpuWithRegisters == null) 151 { 152 cpu.Log(LogLevel.Error, "Current CPU is not of type ICPUWithRegisters"); 153 return; 154 } 155 cpuWithRegisters.IsHalted = true; 156 machine.LocalTimeSource.ExecuteInNearestSyncedState((__) => 157 { 158 var systemBus = machine.SystemBus; 159 160 if(systemBus.WhatPeripheralIsAt(RomRemapAddress) != this.rom) 161 { 162 this.ErrorLog("ROM cannot be unregisted from 0x{0:X} because it is not registered at this address"); 163 return; 164 } 165 166 systemBus.UnregisterFromAddress(RomRemapAddress); 167 systemBus.Register(this.eflashDataText, new BusPointRegistration(RomRemapAddress)); 168 // SP is register is not available in the interface, so we have to set it manually 169 // ArmRegisters is in another project, so we can't use it here 170 const int SP = 13; 171 const int PCValueInELF = 0x4; 172 const int SPValueInELF = 0x0; 173 cpuWithRegisters.PC = systemBus.ReadDoubleWord(PCValueInELF); 174 cpuWithRegisters.SetRegister(SP, systemBus.ReadDoubleWord(SPValueInELF)); 175 cpuWithRegisters.Log(LogLevel.Info, "Successfully remapped eflash to address 0x{0:X}, restarting machine", RomRemapAddress); 176 cpuWithRegisters.Log(LogLevel.Info, "PC set to 0x{0:X}, SP set to 0x{1:X}", cpuWithRegisters.PC.RawValue, cpuWithRegisters.GetRegister(SP).RawValue); 177 cpuWithRegisters.IsHalted = false; 178 }); 179 }) 180 .WithReservedBits(16, 16); 181 182 Registers.SystemStatus.Define(this, 0x95A5) 183 .WithFlag(0, FieldMode.Read, name: "RAD_IS_DOWN", valueProviderCallback: _ => radioSleep.Value) 184 .WithFlag(1, FieldMode.Read, name: "RAD_IS_UP", valueProviderCallback: _ => !radioSleep.Value) 185 .WithFlag(2, FieldMode.Read, name: "PER_IS_DOWN", valueProviderCallback: _ => periphSleep.Value) 186 .WithFlag(3, FieldMode.Read, name: "PER_IS_UP", valueProviderCallback: _ => !periphSleep.Value) 187 .WithFlag(4, FieldMode.Read, name: "SYS_IS_DOWN", valueProviderCallback: _ => sysSleep.Value) 188 .WithFlag(5, FieldMode.Read, name: "SYS_IS_UP", valueProviderCallback: _ => !sysSleep.Value) 189 .WithFlag(6, FieldMode.Read, name: "MEM_IS_DOWN") 190 .WithFlag(7, FieldMode.Read, name: "MEM_IS_UP") 191 .WithFlag(8, FieldMode.Read, name: "TIM_IS_DOWN", valueProviderCallback: _ => timSleep.Value) 192 .WithFlag(9, FieldMode.Read, name: "TIM_IS_UP", valueProviderCallback: _ => !timSleep.Value) 193 .WithFlag(10, FieldMode.Read, name: "COM_IS_DOWN", valueProviderCallback: _ => comSleep.Value) 194 .WithFlag(11, FieldMode.Read, name: "COM_IS_UP", valueProviderCallback: _ => !comSleep.Value) 195 .WithFlag(12, FieldMode.Read, name: "AUD_IS_DOWN", valueProviderCallback: _ => audSleep.Value) 196 .WithFlag(13, FieldMode.Read, name: "AUD_IS_UP", valueProviderCallback: _ => !audSleep.Value) 197 .WithFlag(14, FieldMode.Read, name: "DBG_IS_ACTIVE") 198 .WithFlag(15, FieldMode.Read, name: "POWER_IS_UP") 199 .WithReservedBits(16, 16); 200 201 Registers.ClockRCLP.Define(this, 0x38) 202 .WithFlag(0, name: "RCLP_DISABLE") 203 .WithFlag(1, name: "RCLP_HIGH_SPEED_FORCE") 204 .WithFlag(2, name: "RCLP_LOW_SPEED_FORCE") 205 .WithValueField(3, 4, name: "RCLP_TRIM") 206 .WithReservedBits(7, 25); 207 208 Registers.ClockXTAL32.Define(this, 0x82E) 209 .WithFlag(0, name: "XTAL32K_ENABLE") 210 .WithValueField(1, 2, name: "XTAL32K_RBIAS") 211 .WithValueField(3, 4, name: "XTAL32K_CUR") 212 .WithFlag(7, name: "XTAL32K_DISABLE_AMPREG") 213 .WithReservedBits(8, 1) 214 .WithValueField(9, 4, name: "XTAL32K_VDDX_TRIM") 215 .WithReservedBits(13, 19); 216 217 Registers.ClockRC32M.Define(this, 0x3CE) 218 .WithFlag(0, out rc32mEnable, name: "RC32M_ENABLE", 219 writeCallback: (_, value) => 220 { 221 if(value) 222 { 223 systemClock.Value = SystemClock.RC32M; 224 } 225 }) 226 .WithValueField(1, 4, name: "RC32M_BIAS") 227 .WithValueField(5, 2, name: "RC32M_RANGE") 228 .WithValueField(7, 4, name: "RC32M_COSC") 229 .WithReservedBits(11, 21); 230 231 Registers.ClockRCX.Define(this, 0x57E) 232 .WithFlag(0, name: "RCX_ENABLE") 233 .WithValueField(1, 5, name: "RCX_CADJUST") 234 .WithFlag(6, name: "RCX_C0") 235 .WithValueField(7, 4, name: "RCX_BIAS") 236 .WithReservedBits(11, 21); 237 238 Registers.BandGap.Define(this) 239 .WithValueField(0, 5, name: "BGR_TRIM") 240 .WithReservedBits(5, 1) 241 .WithValueField(6, 5, name: "BGR_ITRIM") 242 .WithReservedBits(11, 21); 243 244 Registers.ResetPadLatch0.Define(this) 245 .WithValueField(0, 16, name: "P0_RESET_LATCH_EN") 246 .WithReservedBits(16, 16); 247 248 Registers.ResetPadLatch1.Define(this) 249 .WithValueField(0, 16, name: "P1_RESET_LATCH_EN") 250 .WithReservedBits(16, 16); 251 252 Registers.BiasVRef.Define(this) 253 .WithValueField(0, 4, name: "BIAS_VREF_RF1_SEL") 254 .WithValueField(4, 4, name: "BIAS_VREF_RF2_SEL") 255 .WithReservedBits(8, 24); 256 257 Registers.ResetStatus.Define(this, 0x3F) 258 .WithFlag(0, name: "PORESET_STAT") 259 .WithFlag(1, name: "HWRESET_STAT") 260 .WithFlag(2, name: "SWRESET_STAT") 261 .WithFlag(3, name: "WDOGRESET_STAT") 262 .WithFlag(4, name: "SWD_HWRESET_STAT") 263 .WithFlag(5, name: "CMAC_WDOGRESET_STAT") 264 .WithReservedBits(6, 26); 265 266 Registers.SecureBoot.Define(this) 267 .WithFlag(0, name: "PROT_CONFIG_SCRIPT") 268 .WithFlag(1, name: "PROT_APP_KEY") 269 .WithFlag(2, name: "PROT_VALID_KEY") 270 .WithFlag(3, name: "PROT_USER_APP_CODE") 271 .WithFlag(4, name: "FORCE_M33_DEBUGGER_OFF") 272 .WithFlag(5, name: "FORCE_CMAC_DEBUGGER_OFF") 273 .WithFlag(6, name: "SECURE_BOOT") 274 .WithReservedBits(7, 1) 275 .WithFlag(8, name: "PROT_INFO_PAGE") 276 .WithReservedBits(9, 23); 277 278 Registers.BODControl.Define(this, 0xC0) 279 .WithValueField(0, 2, name: "BOD_SEL_VDD_LVL") 280 .WithFlag(2, out bodVdddOkSyncRd, name: "BIS_VDD_COMP", 281 writeCallback: (_, value) => bodVdddOkSyncRd.Value = true) 282 .WithFlag(3, out bodVdcdcOkSyncRd, name: "BOD_DIS_VDCDC_COMP", 283 writeCallback: (_, value) => bodVdcdcOkSyncRd.Value = true) 284 .WithFlag(4, out bodVddioOkSyncRd, name: "BOD_DIS_VDDIO_COMP", 285 writeCallback: (_, value) => bodVddioOkSyncRd.Value = true) 286 .WithReservedBits(5, 1) 287 .WithFlag(6, out bodVdddMaskSyncRd, name: "BOD_VDD_MASK", 288 writeCallback: (_, value) => bodVdddMaskSyncRd.Value = value) 289 .WithFlag(7, out bodVdcdcMaskSyncRd, name: "BOD_VDCDC_MASK", 290 writeCallback: (_, value) => bodVdcdcMaskSyncRd.Value = value) 291 .WithFlag(8, out bodVddioMaskSyncRd, name: "BOD_VDDIO_MASK", 292 writeCallback: (_, value) => bodVddioMaskSyncRd.Value = value) 293 .WithReservedBits(9, 23); 294 295 Registers.AnalogStatus.Define(this) 296 .WithFlag(0, FieldMode.Read, name: "BANDGAP_OK", valueProviderCallback: _ => true) 297 .WithFlag(1, FieldMode.Read, name: "LDO_CORE_OK", valueProviderCallback: _ => true) 298 .WithFlag(2, FieldMode.Read, name: "LDO_LOW_OK", valueProviderCallback: _ => true) 299 .WithFlag(3, FieldMode.Read, name: "LDO_IO_OK", valueProviderCallback: _ => true) 300 .WithFlag(4, FieldMode.Read, name: "BOD_COMP_VDD_OK", valueProviderCallback: _ => true) 301 .WithFlag(5, FieldMode.Read, name: "BOD_COMP_VDDIO_OK", valueProviderCallback: _ => true) 302 .WithFlag(6, FieldMode.Read, name: "BOD_COMP_VDCDC_OK", valueProviderCallback: _ => true) 303 .WithFlag(7, FieldMode.Read, name: "BOD_COMP_VEFLASH_OK", valueProviderCallback: _ => true) 304 .WithFlag(8, FieldMode.Read, name: "LDO_GPADC_OK", valueProviderCallback: _ => true) 305 .WithReservedBits(9, 23); 306 307 Registers.PowerControl.Define(this, 0x6517) 308 .WithFlag(0, name: "LDO_IO_ENABLE") 309 .WithFlag(1, name: "LDO_LOW_ENABLE_ACTIVE") 310 .WithFlag(2, name: "LDO_CORE_ENABLE") 311 .WithFlag(3, name: "LDO_IO_RET_ENABLE_ACTIVE") 312 .WithFlag(4, name: "LDO_IO_RET_ENABLE_SLEEP") 313 .WithFlag(5, name: "LDO_IO_BYPASS_ACTIVE") 314 .WithFlag(6, name: "LDO_IO_BYPASS_SLEEP") 315 .WithFlag(7, name: "LDO_LOW_HIGH_CURRENT") 316 .WithFlag(8, name: "LDO_LOW_ENABLE_SLEEP") 317 .WithFlag(9, name: "LDO_CORE_RET_ENABLE_ACTIVE") 318 .WithFlag(10,name: "LDO_CORE_RET_ENABLE_SLEEP") 319 .WithFlag(11,name: "DCDC_ENABLE_SLEEP") 320 .WithFlag(12,name: "LDO_VREF_HOLD_FORCE") 321 .WithFlag(13,name: "LDO_IO_RET_VREF_ENABLE") 322 .WithFlag(14,name: "LDO_CORE_RET_VREF_ENABLE") 323 .WithReservedBits(15, 17); 324 325 Registers.PowerLevel.Define(this) 326 .WithValueField(0, 3, name: "VDD_LEVEL_ACTIVE") 327 .WithFlag(3, name: "VDD_LEVEL_SLEEP") 328 .WithValueField(4, 3, name: "VDCDC_LEVEL") 329 .WithValueField(7, 4, name: "VDDIO_TRIM") 330 .WithValueField(11, 2, name: "XTAL32M_LDO_LEVEL") 331 .WithReservedBits(13, 19); 332 333 Registers.StartUpStatus.Define(this) 334 .WithFlag(0, FieldMode.Read, name: "BOD_VDCDC_MASK_SYNC_RD", valueProviderCallback: _ => bodVdcdcMaskSyncRd.Value) 335 .WithFlag(1, FieldMode.Read, name: "BOD_VDDD_MASK_SYNC_RD", valueProviderCallback: _ => bodVdddMaskSyncRd.Value) 336 .WithFlag(2, FieldMode.Read, name: "BOD_VDDIO_MASK_SYNC_RD", valueProviderCallback: _ => bodVddioMaskSyncRd.Value) 337 .WithValueField(3, 2, FieldMode.Read, name: "BOD_VDDD_LVL_RD") 338 .WithFlag(5, FieldMode.Read, name: "BOD_VDCDC_OK_SYNC_RD", valueProviderCallback: _ => bodVdcdcOkSyncRd.Value) 339 .WithFlag(6, FieldMode.Read, name: "BOD_VDDD_OK_SYNC_RD", valueProviderCallback: _ => bodVdddOkSyncRd.Value) 340 .WithFlag(7, FieldMode.Read, name: "BOD_VDDIO_OK_SYNC_RD", valueProviderCallback: _ => bodVddioOkSyncRd.Value) 341 .WithFlag(8, FieldMode.Read, name: "BOD_VEFLASH_OK_SYNC") 342 .WithFlag(9, FieldMode.Read, name: "VEFLASH_LVL_RD") 343 .WithReservedBits(10, 22); 344 } 345 346 private IMachine machine; 347 private RenesasDA14_XTAL32MRegisters xtal32m; 348 private MappedMemory rom; 349 private MappedMemory eflashDataText; 350 351 private IEnumRegisterField<SystemClock> systemClock; 352 private IFlagRegisterField periphSleep; 353 private IFlagRegisterField radioSleep; 354 private IFlagRegisterField timSleep; 355 private IFlagRegisterField comSleep; 356 private IFlagRegisterField sysSleep; 357 private IFlagRegisterField audSleep; 358 private IEnumRegisterField<RemapAddress> remapAddress; 359 private IFlagRegisterField rc32mEnable; 360 private IFlagRegisterField bodVdddMaskSyncRd; 361 private IFlagRegisterField bodVdcdcMaskSyncRd; 362 private IFlagRegisterField bodVddioMaskSyncRd; 363 private IFlagRegisterField bodVdcdcOkSyncRd; 364 private IFlagRegisterField bodVdddOkSyncRd; 365 private IFlagRegisterField bodVddioOkSyncRd; 366 367 private const int RomRemapAddress = 0x0; 368 369 private enum Registers 370 { 371 ClockAMBA = 0x0, 372 ResetControl = 0xC, 373 RadioPLL = 0x10, 374 ClockControl = 0x14, 375 ClockTimers = 0x18, 376 Switch2XTAL = 0x1C, 377 PMUClock = 0x20, 378 SystemControl = 0x24, 379 SystemStatus = 0x28, 380 ClockRCLP = 0x3C, 381 ClockXTAL32 = 0x40, 382 ClockRC32M = 0x44, 383 ClockRCX = 0x48, 384 ClockRTCDivisor = 0x4C, 385 BandGap = 0x50, 386 PadLatch0 = 0x70, 387 SetPadLatch0 = 0x74, 388 ResetPadLatch0 = 0x78, 389 PadLatch1 = 0x7C, 390 SetPadLatch1 = 0x80, 391 ResetPadLatch1 = 0x84, 392 PORPin = 0x98, 393 PORTimer = 0x9C, 394 BiasVRef = 0xA4, 395 ResetStatus = 0xBC, 396 RamPwrControl = 0xC0, 397 SecureBoot = 0xCC, 398 BODControl = 0xD0, 399 DiscargeRail = 0xD4, 400 AnalogStatus = 0xDC, 401 PowerControl = 0xE0, 402 PowerLevel = 0xE4, 403 HibernationControl = 0xF0, 404 PMUSleepControl = 0xF4, 405 StartUpStatus = 0xFC, 406 } 407 408 private enum SystemClock : byte 409 { 410 XTAL32M = 0x0, 411 RC32M = 0x1, 412 RCLP = 0x2, 413 DBLR64M = 0x3, 414 } 415 416 private enum RemapAddress : byte 417 { 418 ROM = 0x0, 419 EFlash = 0x1, 420 SysRam3 = 0x4, 421 SystemCacheDataRAM = 0x5, 422 NoRemapping = 0x7, 423 } 424 } 425 } 426