When I turned all the templates into inline procs, then it no longer read from 
the register a second time. I also read the gcc's docs about the asm statement 
in greater detail and fixed one register modifier and discovered how to convert 
Nim static args to an assembly immediate operand. With these two details in 
place, I finally got this working as intended. The near-final code will look 
like this:
    
    
    proc setField[T](regVal: T, fieldVal: RegisterVal, bitOffset: static int, 
bitWidth: static int): T {.inline.} =
      {.emit: ["asm (\"BFI %0, %1, %2, %3\"\n\t: \"+r\" (", regVal, ")\n\t: 
\"r\" (", fieldVal, "), \"n\" (", bitOffset, "), \"n\" (", bitWidth, "));\n"].}
      regVal
    
    # reg read
    proc AHB1ENR*(base: static RCC_Base): RCC_AHB1ENR_Val {.inline.} =
      volatileLoad(RCC_AHB1ENR)
    
    # chained field modify
    proc GPIOAEN*(regVal: RCC_AHB1ENR_Val, fieldVal: uint32): RCC_AHB1ENR_Val 
{.inline.} =
      setField[RCC_AHB1ENR_Val](regVal, fieldVal, 0, 1)
    
    # write the modified fields to the reg
    proc write*(regVal: RCC_AHB1ENR_Val) {.inline.} =
      volatileStore(RCC_AHB1ENR, regVal)
    
    proc main() =
      RCC.AHB1ENR         # reg read
         .GPIOAEN(1'u32)  # field modify
         .write()         # reg write
    
    
    Run

I verified that the procs are inlined when the `--passC="-Ox"` is greater than 
1. This will soon be integrated into <https://github.com/dwhall/minisvd2nim>

Reply via email to