Skip to content

Commit

Permalink
Initial Register and BitField macros (#4)
Browse files Browse the repository at this point in the history
Add initial Register and BitField macros

Adds an initial set of macros for declaring symmetric and asymmetric
registers composed of bit fields. The new `@Register` macro can be
applied to a struct only containing stored properties marked with one of
the new bit field macros: `@Reserved`, `@ReadWrite`, `@ReadOnly`, or
`@WriteOnly`.

The bit field macros take bit range argument which the register macro
uses to create three views of the register. The first is a raw view
which provides untyped access to the bits of the register. The second is
a read view which only provides typed getters for the readable bit
fields. The last is a write view which provides setters.

Additional bit field macros such as `@Write1Clear` will be introduced in
a future PR.

Sample usage:
```swift
@register(bitWidth: 32)
struct Example {
    @readwrite(bits: 0..<1)
	var en: EN
}

var example = Register<Example>(...)
example.modify { $0.en = 0x1 }
```

Miscellaneous changes

Rewrites diagnostics system leveraging a new `MacroContext` type which
handles prefixing diagnostics with the name of the macro which produced
them.

Adds helper methods prefixed by "require" to swift-syntax types which
take a macro context, emit a diagnostic and throw `ExpansionError` if
the requirement is not met.

Adds MMIOKindMacro protocol wrappers which suppresses thrown
`ExpansionErrors` to allow macros to be written as simpler straight line
code e.g. `try value.requireSomething(context)`.

Replaces `MacroArgumentParser` with `ParsableMacro` leveraging
`MacroContext` which emits better diagnostics and fix-its.
  • Loading branch information
rauhul committed Oct 6, 2023
1 parent 157742a commit 6c4c1dc
Show file tree
Hide file tree
Showing 41 changed files with 2,893 additions and 601 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lint:
@swift-format lint \
--configuration SupportingFiles/Tools/swift-format/.swift-format \
--recursive \
--strict \
Package.swift Sources Tests

.PHONY: format
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let package = Package(
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0")
],
targets: [
.target(name: "MMIO", dependencies: ["MMIOMacros"]),
.target(name: "MMIO", dependencies: ["MMIOMacros", "MMIOVolatile"]),
.macro(
name: "MMIOMacros",
dependencies: [
Expand All @@ -38,4 +38,5 @@ let package = Package(
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
]),
.target(name: "MMIOVolatile"),
])
26 changes: 26 additions & 0 deletions Sources/MMIO/BitField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

public typealias BitFieldStorage = FixedWidthInteger & UnsignedInteger

public protocol BitField {
associatedtype RawStorage: BitFieldStorage
static var bitRange: Range<Int> { get }
static var bitWidth: Int { get }
static var bitOffset: Int { get }
static var bitMask: RawStorage { get }
}

extension BitField {
public static var bitWidth: Int { self.bitRange.count }
public static var bitOffset: Int { self.bitRange.lowerBound }
public static var bitMask: RawStorage { (1 << self.bitWidth) - 1 }
}
39 changes: 39 additions & 0 deletions Sources/MMIO/Extensions/FixedWidthInteger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

extension FixedWidthInteger {
public subscript<Other: FixedWidthInteger>(
bits range: Range<Int>, as type: Other.Type = Other.self
) -> Other {
@inline(__always) get {
precondition(range.lowerBound >= 0)
precondition(range.upperBound <= Self.bitWidth)
let width = range.upperBound - range.lowerBound
precondition(
width <= Other.bitWidth,
"\(Other.self) cannot accommodate \(width) bits.")
let mask: Self = 1 << width &- 1
return Other(truncatingIfNeeded: self >> range.lowerBound & mask)
}

@inline(__always) set {
precondition(range.lowerBound >= 0)
precondition(range.upperBound <= Self.bitWidth)
let width = range.upperBound - range.lowerBound
precondition(
width <= Other.bitWidth,
"\(Other.self) cannot provide \(width) bits.")
let mask: Self = 1 << width &- 1
self &= ~(mask << range.lowerBound)
self |= (Self(truncatingIfNeeded: newValue) & mask) << range.lowerBound
}
}
}
47 changes: 41 additions & 6 deletions Sources/MMIO/MMIOMacros.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

// RegisterBank macros
@attached(member, names: named(unsafeAddress), named(init))
public macro RegisterBank() =
#externalMacro(
module: "MMIOMacros",
type: "RegisterBankMacro")
#externalMacro(module: "MMIOMacros", type: "RegisterBankMacro")

@attached(accessor)
public macro RegisterBank(offset: Int) =
#externalMacro(
module: "MMIOMacros",
type: "RegisterBankOffsetMacro")
#externalMacro(module: "MMIOMacros", type: "RegisterBankOffsetMacro")

// Register macros
@attached(member, names: arbitrary)
@attached(memberAttribute)
@attached(extension, conformances: RegisterLayout)
public macro Register(bitWidth: Int) =
#externalMacro(module: "MMIOMacros", type: "RegisterMacro")

// Note: Since the 'Reserved' macro shares an implementation with the other
// bitfield macros, it can also handle the `as:` parameter found on their
// external macro declarations. However, this parameter will never be used by
// expansion for reserved bitfields, so it is omitted to avoid programmer use.
@attached(accessor)
public macro Reserved(bits: Range<Int>) =
#externalMacro(module: "MMIOMacros", type: "ReservedMacro")

@attached(accessor)
public macro ReadWrite(bits: Range<Int>) =
#externalMacro(module: "MMIOMacros", type: "ReadWriteMacro")

@attached(accessor)
public macro ReadOnly(bits: Range<Int>) =
#externalMacro(module: "MMIOMacros", type: "ReadOnlyMacro")

@attached(accessor)
public macro WriteOnly(bits: Range<Int>) =
#externalMacro(module: "MMIOMacros", type: "WriteOnlyMacro")
94 changes: 94 additions & 0 deletions Sources/MMIO/MMIOVolatileStorage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import MMIOVolatile

/// A type that represents the raw storage of a volatile value type.
///
/// The set of types which conform to this protocol restricts the the set of
/// volatile operations available on the platform. As such, user code must
/// _never_ conform new types to this protocol.
public protocol MMIOVolatileStorage: BitFieldStorage {
/// Loads an instance of `self` from the address pointed to by pointer.
static func load(from pointer: UnsafePointer<Self>) -> Self
/// Stores an instance of `self` to the address pointed to by pointer.
static func store(_ value: Self, to pointer: UnsafeMutablePointer<Self>)
}

extension UInt8: MMIOVolatileStorage {
/// Loads an instance of `self` from the address pointed to by pointer.
@_transparent
public static func load(from pointer: UnsafePointer<Self>) -> Self {
mmio_volatile_load_uint8_t(pointer)
}

/// Stores an instance of `self` to the address pointed to by pointer.
@_transparent
public static func store(
_ value: Self,
to pointer: UnsafeMutablePointer<Self>
) {
mmio_volatile_store_uint8_t(pointer, value)
}
}

extension UInt16: MMIOVolatileStorage {
/// Loads an instance of `self` from the address pointed to by pointer.
@_transparent
public static func load(from pointer: UnsafePointer<Self>) -> Self {
mmio_volatile_load_uint16_t(pointer)
}

/// Stores an instance of `self` to the address pointed to by pointer.
@_transparent
public static func store(
_ value: Self,
to pointer: UnsafeMutablePointer<Self>
) {
mmio_volatile_store_uint16_t(pointer, value)
}
}

extension UInt32: MMIOVolatileStorage {
/// Loads an instance of `self` from the address pointed to by pointer.
@_transparent
public static func load(from pointer: UnsafePointer<Self>) -> Self {
mmio_volatile_load_uint32_t(pointer)
}

/// Stores an instance of `self` to the address pointed to by pointer.
@_transparent
public static func store(
_ value: Self,
to pointer: UnsafeMutablePointer<Self>
) {
mmio_volatile_store_uint32_t(pointer, value)
}
}

#if arch(x86_64) || arch(arm64)
extension UInt64: MMIOVolatileStorage {
/// Loads an instance of `self` from the address pointed to by pointer.
@_transparent
public static func load(from pointer: UnsafePointer<Self>) -> Self {
mmio_volatile_load_uint64_t(pointer)
}

/// Stores an instance of `self` to the address pointed to by pointer.
@_transparent
public static func store(
_ value: Self,
to pointer: UnsafeMutablePointer<Self>
) {
mmio_volatile_store_uint64_t(pointer, value)
}
}
#endif
106 changes: 106 additions & 0 deletions Sources/MMIO/MMIOVolatileValue.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

/// A type that supports volatile operations through a separate volatile storage
/// representation.
public protocol MMIOVolatileValue {
// FIXME: Remove need for MMIOVolatileRepresentation with compiler support
// All types can be MMIOVolatileValues if they are bitwise copyable and have a
// bit width which maps to platform intrinsic load/store width. This could be
// represented with the following potential future swift.
// extension<Type> Type: MMIOVolatileValue where Type: BitwiseCopyable, MemoryLayout<Type>.size == 1 { }
// extension<Type> Type: MMIOVolatileValue where Type: BitwiseCopyable, MemoryLayout<Type>.size == 2 { }
// extension<Type> Type: MMIOVolatileValue where Type: BitwiseCopyable, MemoryLayout<Type>.size == 4 { }
// extension<Type> Type: MMIOVolatileValue where Type: BitwiseCopyable, MemoryLayout<Type>.size == 8 { }

/// The volatile storage representation for this value.
associatedtype MMIOVolatileRepresentation: MMIOVolatileStorage
/* where Self.bitWidth == MMIOVolatileRepresentation.bitWidth */
}

extension MMIOVolatileValue {
/// Loads an instance of `self` from the address pointed to by pointer.
///
/// First loads Self.MMIOVolatileRepresentation from the pointer, then
/// reinterprets the bits as Self.
@_transparent
static func load(from pointer: UnsafePointer<Self>) -> Self {
pointer.withMemoryRebound(
to: Self.MMIOVolatileRepresentation.self,
capacity: 1
) { pointer in
let value = Self.MMIOVolatileRepresentation.load(from: pointer)
return unsafeBitCast(value, to: Self.self)
}
}

/// Stores an instance of `self` to the address pointed to by pointer.
///
/// First reinterprets the bits of Self as Self.MMIOVolatileRepresentation,
/// then stores the bits to the pointer.
@_transparent
static func store(_ value: Self, to pointer: UnsafeMutablePointer<Self>) {
pointer.withMemoryRebound(
to: MMIOVolatileRepresentation.self,
capacity: 1
) { pointer in
let value = unsafeBitCast(
value,
to: MMIOVolatileRepresentation.self
)
Self.MMIOVolatileRepresentation.store(value, to: pointer)
}
}
}

extension UInt8: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt8
}

extension UInt16: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt16
}

extension UInt32: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt32
}

#if arch(x86_64) || arch(arm64)
extension UInt64: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt64
}
#endif

extension Int8: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt8
}

extension Int16: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt16
}

extension Int32: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt32
}

#if arch(x86_64) || arch(arm64)
extension Int64: MMIOVolatileValue {
/// The volatile storage representation for this value.
public typealias MMIOVolatileRepresentation = UInt64
}
#endif
Loading

0 comments on commit 6c4c1dc

Please sign in to comment.