Last active
August 4, 2024 22:20
-
-
Save RX14/48b277239c2b0974eff9bf0e37bff373 to your computer and use it in GitHub Desktop.
Example SVD codegen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (c) 2020 Raspberry Pi (Trading) Ltd. | |
# | |
# SPDX-License-Identifier: BSD-3-Clause | |
# Controls the crystal oscillator | |
module XOSC | |
VERSION = "1" | |
BASE_ADDRESS = 0x40024000_u64 | |
# Crystal Oscillator Control | |
struct CTRL | |
ADDRESS = BASE_ADDRESS + 0x0_u64 | |
@value : UInt32 | |
def initialize(@value : UInt32) | |
end | |
def to_i : UInt32 | |
@value | |
end | |
def self.reset_value : self | |
new(0x0_u64) | |
end | |
def self.pointer : Pointer(UInt32) | |
Pointer(UInt32).new(ADDRESS) | |
end | |
def self.value : self | |
value = Atomic::Ops.load(self.pointer, :not_atomic, volatile: true) | |
new(value) | |
end | |
def self.value=(value : self) : self | |
Atomic::Ops.store(self.pointer, value.to_i, :not_atomic, volatile: true) | |
value | |
end | |
enum ENABLE : UInt16 | |
DISABLE = 0xd1e_u64 | |
ENABLE = 0xfab_u64 | |
end | |
# On power-up this field is initialised to DISABLE and the chip runs from the ROSC. | |
# If the chip has subsequently been programmed to run from the XOSC then setting this field to DISABLE may lock-up the chip. If this is a concern then run the clk_ref from the ROSC and enable the clk_sys RESUS feature. | |
# The 12-bit code is intended to give some protection against accidental writes. An invalid setting will enable the oscillator. | |
def enable : ENABLE | |
ENABLE.new(@value.unsafe_shr(12) & 0xfff_u32) | |
end | |
# On power-up this field is initialised to DISABLE and the chip runs from the ROSC. | |
# If the chip has subsequently been programmed to run from the XOSC then setting this field to DISABLE may lock-up the chip. If this is a concern then run the clk_ref from the ROSC and enable the clk_sys RESUS feature. | |
# The 12-bit code is intended to give some protection against accidental writes. An invalid setting will enable the oscillator. | |
def self.enable : ENABLE | |
value.enable | |
end | |
# On power-up this field is initialised to DISABLE and the chip runs from the ROSC. | |
# If the chip has subsequently been programmed to run from the XOSC then setting this field to DISABLE may lock-up the chip. If this is a concern then run the clk_ref from the ROSC and enable the clk_sys RESUS feature. | |
# The 12-bit code is intended to give some protection against accidental writes. An invalid setting will enable the oscillator. | |
def self.enable=(value : ENABLE) : ENABLE | |
pointer.value = (pointer.value & 0xff000fff_u32) | | |
(value.to_i & 0xfff_u32).unsafe_shl(12) | |
value | |
end | |
enum FREQ_RANGE : UInt16 | |
VAL_115MHZ = 0xaa0_u64 | |
RESERVED1 = 0xaa1_u64 | |
RESERVED2 = 0xaa2_u64 | |
RESERVED3 = 0xaa3_u64 | |
end | |
# Frequency range. This resets to 0xAA0 and cannot be changed. | |
def freq_range : FREQ_RANGE | |
FREQ_RANGE.new(@value.unsafe_shr(0) & 0xfff_u32) | |
end | |
# Frequency range. This resets to 0xAA0 and cannot be changed. | |
def self.freq_range : FREQ_RANGE | |
value.freq_range | |
end | |
# Frequency range. This resets to 0xAA0 and cannot be changed. | |
def self.freq_range=(value : FREQ_RANGE) : FREQ_RANGE | |
pointer.value = (pointer.value & 0xfffff000_u32) | | |
(value.to_i & 0xfff_u32).unsafe_shl(0) | |
value | |
end | |
def copy_with( | |
*, | |
enable : ENABLE? = nil, | |
freq_range : FREQ_RANGE? = nil, | |
) : self | |
value = @value | |
unless enable.nil? | |
value = (value & 0xff000fff_u32) | | |
(enable.to_i & 0xfff_u32).unsafe_shl(12) | |
end | |
unless freq_range.nil? | |
value = (value & 0xfffff000_u32) | | |
(freq_range.to_i & 0xfff_u32).unsafe_shl(0) | |
end | |
self.class.new(value) | |
end | |
def self.set(**kwargs) : Nil | |
self.value = self.value.copy_with(**kwargs) | |
end | |
end | |
# Crystal Oscillator Status | |
struct STATUS | |
ADDRESS = BASE_ADDRESS + 0x4_u64 | |
@value : UInt32 | |
def initialize(@value : UInt32) | |
end | |
def to_i : UInt32 | |
@value | |
end | |
def self.reset_value : self | |
new(0x0_u64) | |
end | |
def self.pointer : Pointer(UInt32) | |
Pointer(UInt32).new(ADDRESS) | |
end | |
def self.value : self | |
value = Atomic::Ops.load(self.pointer, :not_atomic, volatile: true) | |
new(value) | |
end | |
def self.value=(value : self) : self | |
Atomic::Ops.store(self.pointer, value.to_i, :not_atomic, volatile: true) | |
value | |
end | |
# Oscillator is running and stable | |
def stable : Bool | |
@value.bits_set?(0x80000000_u32) | |
end | |
# Oscillator is running and stable | |
def self.stable : Bool | |
value.stable | |
end | |
# An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or DORMANT | |
def badwrite : Bool | |
@value.bits_set?(0x1000000_u32) | |
end | |
# An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or DORMANT | |
def self.badwrite : Bool | |
value.badwrite | |
end | |
# An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or DORMANT | |
def self.badwrite=(value : Bool) : Bool | |
pointer.value = (pointer.value & 0xfeffffff_u32) | | |
(value.to_i & 0x1_u32).unsafe_shl(24) | |
value | |
end | |
# Oscillator is enabled but not necessarily running and stable, resets to 0 | |
def enabled : Bool | |
@value.bits_set?(0x1000_u32) | |
end | |
# Oscillator is enabled but not necessarily running and stable, resets to 0 | |
def self.enabled : Bool | |
value.enabled | |
end | |
enum FREQ_RANGE : UInt8 | |
VAL_115MHZ = 0x0_u64 | |
RESERVED1 = 0x1_u64 | |
RESERVED2 = 0x2_u64 | |
RESERVED3 = 0x3_u64 | |
end | |
# The current frequency range setting, always reads 0 | |
def freq_range : FREQ_RANGE | |
FREQ_RANGE.new(@value.unsafe_shr(0) & 0x3_u32) | |
end | |
# The current frequency range setting, always reads 0 | |
def self.freq_range : FREQ_RANGE | |
value.freq_range | |
end | |
def copy_with( | |
*, | |
badwrite : Bool? = nil, | |
) : self | |
value = @value | |
unless badwrite.nil? | |
value = (value & 0xfeffffff_u32) | | |
(badwrite.to_i & 0x1_u32).unsafe_shl(24) | |
end | |
self.class.new(value) | |
end | |
def self.set(**kwargs) : Nil | |
self.value = self.value.copy_with(**kwargs) | |
end | |
end | |
# Crystal Oscillator pause control | |
# This is used to save power by pausing the XOSC | |
# On power-up this field is initialised to WAKE | |
# An invalid write will also select WAKE | |
# WARNING: stop the PLLs before selecting dormant mode | |
# WARNING: setup the irq before selecting dormant mode | |
struct DORMANT | |
ADDRESS = BASE_ADDRESS + 0x8_u64 | |
@value : UInt32 | |
def initialize(@value : UInt32) | |
end | |
def to_i : UInt32 | |
@value | |
end | |
def self.reset_value : self | |
new(0x0_u64) | |
end | |
def self.pointer : Pointer(UInt32) | |
Pointer(UInt32).new(ADDRESS) | |
end | |
def self.value : self | |
value = Atomic::Ops.load(self.pointer, :not_atomic, volatile: true) | |
new(value) | |
end | |
def self.value=(value : self) : self | |
Atomic::Ops.store(self.pointer, value.to_i, :not_atomic, volatile: true) | |
value | |
end | |
end | |
# Controls the startup delay | |
struct STARTUP | |
ADDRESS = BASE_ADDRESS + 0xc_u64 | |
@value : UInt32 | |
def initialize(@value : UInt32) | |
end | |
def to_i : UInt32 | |
@value | |
end | |
def self.reset_value : self | |
new(0xc4_u64) | |
end | |
def self.pointer : Pointer(UInt32) | |
Pointer(UInt32).new(ADDRESS) | |
end | |
def self.value : self | |
value = Atomic::Ops.load(self.pointer, :not_atomic, volatile: true) | |
new(value) | |
end | |
def self.value=(value : self) : self | |
Atomic::Ops.store(self.pointer, value.to_i, :not_atomic, volatile: true) | |
value | |
end | |
# Multiplies the startup_delay by 4. This is of little value to the user given that the delay can be programmed directly. | |
def x4 : Bool | |
@value.bits_set?(0x100000_u32) | |
end | |
# Multiplies the startup_delay by 4. This is of little value to the user given that the delay can be programmed directly. | |
def self.x4 : Bool | |
value.x4 | |
end | |
# Multiplies the startup_delay by 4. This is of little value to the user given that the delay can be programmed directly. | |
def self.x4=(value : Bool) : Bool | |
pointer.value = (pointer.value & 0xffefffff_u32) | | |
(value.to_i & 0x1_u32).unsafe_shl(20) | |
value | |
end | |
# in multiples of 256*xtal_period. The reset value of 0xc4 corresponds to approx 50 000 cycles. | |
def delay : UInt16 | |
UInt16.new(@value.unsafe_shr(0) & 0x3fff_u32) | |
end | |
# in multiples of 256*xtal_period. The reset value of 0xc4 corresponds to approx 50 000 cycles. | |
def self.delay : UInt16 | |
value.delay | |
end | |
# in multiples of 256*xtal_period. The reset value of 0xc4 corresponds to approx 50 000 cycles. | |
def self.delay=(value : UInt16) : UInt16 | |
pointer.value = (pointer.value & 0xffffc000_u32) | | |
(value.to_i & 0x3fff_u32).unsafe_shl(0) | |
value | |
end | |
def copy_with( | |
*, | |
x4 : Bool? = nil, | |
delay : UInt16? = nil, | |
) : self | |
value = @value | |
unless x4.nil? | |
value = (value & 0xffefffff_u32) | | |
(x4.to_i & 0x1_u32).unsafe_shl(20) | |
end | |
unless delay.nil? | |
value = (value & 0xffffc000_u32) | | |
(delay.to_i & 0x3fff_u32).unsafe_shl(0) | |
end | |
self.class.new(value) | |
end | |
def self.set(**kwargs) : Nil | |
self.value = self.value.copy_with(**kwargs) | |
end | |
end | |
# A down counter running at the xosc frequency which counts to zero and stops. | |
# To start the counter write a non-zero value. | |
# Can be used for short software pauses when setting up time sensitive hardware. | |
struct COUNT | |
ADDRESS = BASE_ADDRESS + 0x1c_u64 | |
@value : UInt32 | |
def initialize(@value : UInt32) | |
end | |
def to_i : UInt32 | |
@value | |
end | |
def self.reset_value : self | |
new(0x0_u64) | |
end | |
def self.pointer : Pointer(UInt32) | |
Pointer(UInt32).new(ADDRESS) | |
end | |
def self.value : self | |
value = Atomic::Ops.load(self.pointer, :not_atomic, volatile: true) | |
new(value) | |
end | |
def self.value=(value : self) : self | |
Atomic::Ops.store(self.pointer, value.to_i, :not_atomic, volatile: true) | |
value | |
end | |
def count : UInt8 | |
UInt8.new(@value.unsafe_shr(0) & 0xff_u32) | |
end | |
def self.count : UInt8 | |
value.count | |
end | |
def self.count=(value : UInt8) : UInt8 | |
pointer.value = (pointer.value & 0xffffff00_u32) | | |
(value.to_i & 0xff_u32).unsafe_shl(0) | |
value | |
end | |
def copy_with( | |
*, | |
count : UInt8? = nil, | |
) : self | |
value = @value | |
unless count.nil? | |
value = (value & 0xffffff00_u32) | | |
(count.to_i & 0xff_u32).unsafe_shl(0) | |
end | |
self.class.new(value) | |
end | |
def self.set(**kwargs) : Nil | |
self.value = self.value.copy_with(**kwargs) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment