Skip to content

Instantly share code, notes, and snippets.

@RX14
Last active August 4, 2024 22:20
Show Gist options
  • Save RX14/48b277239c2b0974eff9bf0e37bff373 to your computer and use it in GitHub Desktop.
Save RX14/48b277239c2b0974eff9bf0e37bff373 to your computer and use it in GitHub Desktop.
Example SVD codegen
# 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