Skip to content

Add support for RP2040 #14

@demotomohiro

Description

@demotomohiro

I used svd2nim for SVD file for RP2040 in https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2040/hardware_regs/RP2040.svd
But procedures in generated module rp2040.nim doesn't write registers atomitically.

Please read '2.1.2. Atomic Register Access' in RP2040 Datasheet in https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
This header file in Raspberry Pi Pico SDK wraps atomic memory accesses:
https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_base/include/hardware/address_mapped.h

modifyIt templates should not be generated for RP2040 as it seems cannot be atomic.
I think following procs should to be added:

# Common procs for writing RP2040 registers.
# Not exported.
const
  RegAliasXorBits = 0x1000'u32
  RegAliasSetBits = 0x2000'u32
  RegAliasClrBits = 0x3000'u32

proc storeToReg(reg: object; mask: uint32; regAlias: uint32) {.inline.} =
  volatileStore(cast[ptr uint32](cast[uint32](reg.loc) or regAlias), mask)

# You can use setBits/clearBits/xorBits for modifying 1 bit bool fields in a register.
# When you write int or enum fields in the register, use `writeMasked`.
# Because for example, if you want to set '0b10' to the 2bit field of the register, 
# you need to call `setBits` and `clearBits` but that requires write to the register twice.
# Write to some registers have side effect and you might want to write only once.
proc setBits*(reg: object; mask: uint32) {.inline.} =
  storeToReg(reg, mask, RegAliasSetBits)

proc clearBits*(reg: object; mask: uint32) {.inline.} =
  storeToReg(reg, mask, RegAliasClrBits)

proc xorBits*(reg: object; mask: uint32) {.inline.} =
  storeToReg(reg, mask, RegAliasXorBits)

# Set new values for the bits of register.
# You need to use this when you want to set int/enum type field of a register.
# Concurrent write to different bits is safe but same bits is unsafe.
proc writeMasked*(reg: object; values, writeMask: uint32) =
  xorBits(reg, (volatileLoad(cast[ptr uint32](reg.loc)) xor values) and writeMask)
import std/options

type
  SomeRegister_Fields* = distinct uint32

# It seems `set[SomeEnum]` cannot be used for specific size sets.
# https://github.com/nim-lang/Nim/issues/21789
# So use bitwise operators.
const
  SomeRegisterFieldBit0* = 0x1.SomeRegister_Fields
  SomeRegisterFieldBit1* = 0x2.SomeRegister_Fields
  SomeRegisterFieldBit2* = 0x4.SomeRegister_Fields
  SomeRegisterFieldBit3* = 0x8.SomeRegister_Fields
  ...

# Set only bits that is 1 in `val`.
proc setBits*(reg: Register_Type, val: SomeRegister_Fields) =
  setBits(reg, val)

# Clear only bits that is 1 on `val`.
proc clearBits*(reg: Register_Type, val: SomeRegister_Fields) =
  clearBits(reg, val)

# Flip only bits that is 1 on `val`.
proc xorBits*(reg: Register_Type, val: SomeRegister_Fields)
  xorBits(reg, val)

# For int/enum fields.
proc writeMasked*(reg: Register_Type, Field0 = none(uint32), Field1 = none(SomeEnum), Field2 = none(bool)) =
  var x: uint32
  if Field2.isSome:
    x.setMask((Field2 shl 24).masked(24 .. 24))
  if Field1.isSome:
    x.setMask((Field1.uint32 shl 16).masked(16 .. 23))
  if Field0.isSome:
    x.setMask((Field0 shl 0).masked(0 .. 15))
  reg.writeMasked x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions