I am working on a GPIO IP for Designstart Pro Cortex-M0. Now in my Simulation there are some Read-Modify-Write cycles in order to set only single bits in a 32 bit register.
If the GPIO register is 0x0000000X and I just want to set bit 16, GCC produces [0x0000000X ORRS 0x00010000] and what the ALU makes out of it is then 0xXXXXXXXX.
Is this correct behaviour? I expected the result to be 0x0001000X.
tldr; ALU: [0x0000000X ORRS 0x00010000] = 0xXXXXXXXX
4-state simulation does produce some behaviour that is not always easy to understand, particularly when it comes to overlapping the 'don't care' and 'don't know' results. In short, this is the expected behaviour, but I agree it is not useful.
As to what is going on here, you will find that if you provide either b0 or b1 to the bottom bit of the read data, then everything will work as expected. This is what happens in a real physical chip, the register which wasn't reset and got read will have one of the two legal values, but you can't predict in advance which value it will take. What will not happen would be for that signal to have an indeterminate value (Vcc/2, or bad setup/hold). Every logic gate will behave in a deterministic way, and the design works according to the architecture.
In simulation, the simulator uses X to indicate that you're reading a register which hasn't been written to. Most of the time, these 'don't know' values behave as you would expect. Applied to simple logic functions or gated flops, the 'don't know' state is usually confined to a part of the circuit where it is not observed. You have observed that it can be loaded into one of the architectural registers with no problem.
Where the problem does become observable is when the 'don't know' is applied to the input of a case statement or ternary operator in Verilog (but not an if statement). Unless the case statement has explicit 'don't care' coding, the 'don't know' input will map to a 'don't know' output. This is referred to as 'pessimistic X-propogation' and is usually safer from a validation point of view than treating unknown values as having the same behaviour as one of the known states.
In terms of which instructions will expose a case statement to an un-initialised register value, it is not easy to predict this (or even to trace the logic path given an example). Many complex designs will show this sort of behaviour, and it seems reasonable that the ALU will have several areas which perform several functions depending on the state of various registers.
In terms of how to proceed, there are two choices. Either you arrange to clear the unknown state (by using a reset, or performing an access to reset the register), or you initialise the problematic state in the simulator before it is consumed. If you chose the latter and you are actually tasked with verifying the ALU design, you would need to test both the 0 and 1 states which this logic can be exposed to. In this case, the ALU is verified as part of the processor so it is less of a concern for you.
This behaviour is the reason that you will see boot code for a processor sometimes initializes the core architectural registers. In silicon, this is not necessary, but for simulation you will risk seeing odd X-prop behaviour (particularly with small C programs that only use some of the registers involved in the APCS).