If I did wait for the clock, what is the 'rule of thumb' for signals changing at the clock edge? For example:

`always @(posedge clk or negedge clk)`

a <= clk;

always @(posedge clk)

data <= a;

Can I really rely on this that a or data will be the 'new' values 100% of the time?

In this case (and it's bizarre and you'd never do it, but ...), what will happen is clear.

On the rising edge of

clk, we look at the current values of

clk and

a. Assuming an initializer on

a (clearing to 0), and that a rising edge means

clk is 1, this means we schedule an assignment to a of 1, and we schedule an assignment to

data of 0 (the initial value of

a).

The next thing that happens (of interest) is a falling edge on

clk. This schedules a new assignment to

a, of 0. Since the other always block is not sensitive to the falling edge of

clk, it doesn't get triggered.

data remains the same.

Then there's another rising edge of

clk. This again schedules a new assignment of 1 to

a. It also schedules a new assignment to

data. It uses the current value of

a -- which is 0 (from the negedge event).

And so forth. It helps to draw it out on paper.