Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Register and BitField macros #4

Merged
merged 6 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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