svd2rust icon indicating copy to clipboard operation
svd2rust copied to clipboard

"overloaded" registers

Open japaric opened this issue 7 years ago • 14 comments

File: STM32F30x.svd Peripheral: TIM2

The SVD file specifies that two registers exist at offset 0x1C: CCMR2_Input and CCMR2_Output. The thing is that this register can be used differently depending on whether the TIM2 peripheral is configured in Output Compare Mode or in Input Compare Mode. By differently, I mean that the bits of this register have different meaning depending on the compare mode.

I'm not sure how to model this. We could use a union here but that's not stable. For now, I think, I'm just going to pick one register and ignore the other but emit a warning.

japaric avatar Oct 20 '16 04:10 japaric

One approach would be to make both registers available but disable any constraints that would make read or write access to the register safe.

cwoodall avatar Apr 11 '17 03:04 cwoodall

Having a similar issue with an STM32F103. The MODE register of a GPIO configures it for input or output, the CNF register handles the configuration (open-drain, push-pull, etc) but the settings are different depending on the mode.

edit: not entirely the same issue, this could be handled by commands having aliases, the register is still the same.

etrombly avatar May 11 '17 04:05 etrombly

I think I've run into this as well.

Trying to use the generated file from: https://github.com/nicholastmosher/lpc176x5x-rs/blob/master/src/uart.rs which has a register called "DLL", but because it overlaps with the "RBR" register at offset 0x0, it cannot be used at all.

The SVD file used (https://raw.githubusercontent.com/posborne/cmsis-svd/aa4721af946a253d18c8737b01d23e9c88a42e84/data/NXP/LPC176x5x_v0.2.svd) annotates this with "alternateRegister".

So, "+1" I guess.

silven avatar Jun 27 '17 18:06 silven

To @etrombly. I solved this problem by changing field definitions in SVD file. CNF and MODE bits for the same pin are adjacent so instead of separate 2-bit fields I declared them as one 4-bit field. And then created enum for them according to the "Table 20. Port bit configuration table" in the reference manual. So now I can select mode with single call like "output10pp" (Output, push-pull, max speed 10MHz) or "input_floating".

But there are cases where such solution is not possible. I think that in situation like example with timers it will be best to generate API for both registers (maybe just print a warning about it during generation). And then programmer can use appropriate API depending of the mode.

Just checked SVD file for stm32f103. Registers CCMR1_Input and CCMR1_Output even have attribute alternateRegister which exists exactly for such cases. So I think that in cases where registers explicitly marked as alternate variants using this attribute svd2rust can give access to both. And in other cases overlapping registers should be considered error in SVD file.

protomors avatar Jun 28 '17 16:06 protomors

SVD files I am generating for MSP430 are also affected by this issue, but since the overlapping registers are not in the same peripheral, the svd2rust does not complain about them.

pftbest avatar Jun 29 '17 13:06 pftbest

@pftbest

but since the overlapping registers are not in the same peripheral,

Could you elaborate on this? How can they be overlapping if the registers are in different peripherals? What would be an example of this in the SVD file you linked?

japaric avatar Jun 29 '17 22:06 japaric

How can they be overlapping if the registers are in different peripherals?

On MSP430 the peripheral (module) is a logical group of registers, not physical group. Each register of a peripheral may be placed in some random location in memory. In practice almost all peripherals overlap with each other, but it's not a problem since they have a different combination of registers and reserved fields inside.

But there are some peripherals that do contain overlapping registers, for example USCI_B0_SPI_Mode and USCI_B0_I2C_Mode

pftbest avatar Jun 30 '17 02:06 pftbest

Adding some context here (as I keep stumbling at ccmr1_input/ccmr1_output registers on STM32 F103 chip).

First, unions are in Rust 1.19: https://github.com/rust-lang/rust/pull/42068

However, using them at this point would require breaking the API as anonymous unions are not supported (i.e, instead of tim1.ccmr1_output(...) / tim1.ccmr1_input.write(...) access pattern would be like tim1.ccmr1_output.ccmr1_output.write(...) / tim1.ccmr1_output.ccmr1_input.write(...) (first ccmr1_output is the name of the group). Anonymous unions are currently discussed here.

idubrov avatar Sep 19 '17 00:09 idubrov

I think this currently bites me as well with the LPC11Uxx:

<register>
	<name>RBR</name>
	<description>Receiver Buffer Register. Contains the next received character to be read. (DLAB=0)</description>
	<addressOffset>0x000</addressOffset>
	<access>read-only</access>
	<resetValue>0</resetValue>
	<resetMask>0x00000000</resetMask>
	<readAction>modify</readAction>
	<fields>
		<field>
			<name>RBR</name>
			<description>The USART Receiver Buffer Register contains the oldest received byte in the USART RX FIFO.</description>
			<bitRange>[7:0]</bitRange>
		</field>
		<field>
			<name>RESERVED</name>
			<description>Reserved</description>
			<bitRange>[31:8]</bitRange>
		</field>
	</fields>
</register>
<register>
	<name>THR</name>
	<description>Transmit Holding Register. The next character to be transmitted is written here. (DLAB=0)</description>
	<alternateRegister>RBR</alternateRegister>
	<addressOffset>0x000</addressOffset>
	<access>write-only</access>
	<resetValue>0</resetValue>
	<resetMask>0x00000000</resetMask>
	<readAction>modify</readAction>
	<fields>
		<field>
			<name>THR</name>
			<description>Writing to the USART Transmit Holding Register causes the data to be stored in the USART transmit FIFO. The byte will be sent when it is the oldest byte in the FIFO and the transmitter is available.</description>
			<bitRange>[7:0]</bitRange>
		</field>
		<field>
			<name>RESERVED</name>
			<description>Reserved</description>
			<bitRange>[31:8]</bitRange>
		</field>
	</fields>
</register>

The receive and transmit buffer register are mapped to the same address. Here it would be actually the best to just have both available.

rnestler avatar Dec 29 '17 01:12 rnestler

I have some code that does something about this using unions. https://github.com/japaric/svd2rust/pull/192#issuecomment-373077513 has an example of how this looks. If you have strong opinions on naming/modeling, or if there are really bizarre situations that need to be accounted for, I'd love to hear them.

wez avatar Mar 14 '18 16:03 wez

I have some code that does something about this using unions. #192 (comment) has an example of how this looks. If you have strong opinions on naming/modeling, or if there are really bizarre situations that need to be accounted for, I'd love to hear them.

I think for the LPC11uxx use case above a union isn't really the right thing, since the read and write register are unrelated. So we could just generate a read and a write struct for each and it would be fine. I'd be willing to implement support for that in svd2rust, so that if we have exactly one read and one write representation of a register we'll just generate them without a union.

rnestler avatar Jun 04 '18 19:06 rnestler

@japaric would the approach proposed by @rnestler be sensible? solving this issue is a requirement for properly supporting MCUs like the NXP LPC11Uxx.

dbrgn avatar Jun 14 '18 10:06 dbrgn

I think for the LPC11uxx use case above a union isn't really the right thing, since the read and write register are unrelated.

What does this mean? How are they unrelated

On 14 June 2018 at 12:48, Danilo Bargen [email protected] wrote:

@japaric https://github.com/japaric would the approach proposed by @rnestler https://github.com/rnestler be sensible? solving this issue is a requirement for properly supporting MCUs like the NXP LPC11Uxx.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/japaric/svd2rust/issues/16#issuecomment-397252998, or mute the thread https://github.com/notifications/unsubscribe-auth/ABbuh3qUVBsKDH5VvM2HVmbqRMUHlwiCks5t8j-PgaJpZM4KbtVf .

Emilgardis avatar Jun 14 '18 14:06 Emilgardis

What does this mean? How are they unrelated

The Tx and Rx register for example use the same address. But writing to the Tx register doesn't influence the Rx register at all, they are just mapped to the same address. So one can't write to the Rx register and one can't read from the Tx register.

rnestler avatar Jun 14 '18 15:06 rnestler

Closing as already supported

burrbull avatar Nov 07 '22 19:11 burrbull