A edge-triggered latch (flipflop) ideally samples the data line instantaneously on one of the edges of the clock. However, nothing is truly instantaneous, so the data must be valid for some finite amount of time around the clock edge. The time it must be fixed before the clock edge is called the setup time, and the time it must be fixed after the clock edge is called the hold time.
Added:
Hold time violation is a violation of the hold time requirement. If the datasheet says the minimum required hold time is 10 ns and you change the data 5 ns after the clock edge, then you have committed a hold time violation and there is no guarantee which data value will end up on the flipflop output.
It's all about how the registers are connected to the bus:
if wb_cyc = '1' and wb_stb = '1' then -- accessing the register
if wb_we = '1' then -- writing to the register?
my_reg <= wb_dat_i; -- update register contents
else -- reading from the register
wb_dat_o <= my_reg; -- return register contents
end if;
end if;
If you leave out the part of the hardware that can read the register then your register is write-only. Similarly if you leave out the part of the hardware that can write to the register then it's read-only.
Sometimes it makes sense to have only one "direction" of data flow. Think of a DAC or an ADC data path.
Also, sometimes it makes sense to have the same address return something other than the data you've written to it. Think of most common microcontrollers; their peripherals tend to have a single address that is a "command" for writes and a "status" for reads.
Another example would be interrupt flags: you read the interrupt register to see which peripheral interrupted the program, then write a '1' to the same bit to clear the interrupt flag. One way to realize that is as follows:
wb_dat_o <= (others => '0');
if wb_cyc = '1' and wb_stb = '1' then -- register access
if wb_we = '1' then -- writing to the register?
clear_int <= wb_dat_i(0);
else -- reading from the register?
clear_int <= '0';
wb_dat_o <= running & int_enabled & int_active;
end if;
end if;
Here you can see that I'm setting a flag to whatever is in bit position 0 in the write case (and I don't care about whatever else they may have written), while in the read case I'm building up a status word made up of individual bits that the peripheral is driving.
aside: I am also explicitly maintaining clear_int
at zero in the read case. It's just good coding practice to make sure that all signals are assigned in all code paths in HDL. At best not doing so makes for sloppy code. At worst you can infer latches. Note that I do something similar with wb_dat_o
before I even enter the register access case.
Keep in mind that these are only examples to illustrate the point, and that a well-written program will be described more carefully and thoroughly. Also keep in mind that it's 8am here and I haven't had my coffee yet. :-)
Best Answer
You're forgetting a couple of important facts:
Take this diagram of a transparent latch:
Assume each gate requires one "time unit" to propagate the signal.
The D signal arrives at the input to one NAND gate at \$T_0\$. It also arrives at the NOT gate at \$T_0\$. It then leaves the NOT gate and arrives at the second (lower) NAND gate at \$T_1\$. So the shortest time before the CLK signal can have any effect on the input NAND gates will be \$T_1\$ since that is when the D signal has propagated to them. SO then the output of those NAND gates will be propagated as stable at \$T_1\$ for the upper one, and \$T_2\$ for the lower one. Then it's on to the next two NAND gates. Those again add 1 time unit to each of the signals. On top of that, the outputs of those then feed back into each other's inputs, so as they change they propagate a new signal through themselves, each adding another time unit.
Only when the outputs have stopped sorting themselves out will the gate be "stable", and that is when it's in the "hold" state. It could be many time units.
Then of course you have the "square" wave, which is far from square. Each change from low-to-high or high-to-low takes time. Only once a signal passes a certain threshold will it be seen as either high or low. Different factors affect how long those transitions take, including the gate capacitance of the MOSFETs in the logic gate, the actual switching time of the MOSFETs, etc.
So you can see there is a certain amount of time taken for a flip-flop to change from one state to another, and at different points during that time different things happen with the gate.