The only problem here is now one of deciding in what order devices should listen to each other and what order devices should speak... One of the most common communications protocol here I2C (there are many other variants with alterations in the protocol for different design reasons). Two wires are used to communicate - one for a clock (SCL - serial clock line) and one for data (SDA - serial data line) and these connect to every device. The key is that at any given time there is only one physical device that has logical control of the bus and that device supplies the clock (SCL). If you think about it there are only 2 timing signals (positive and negative edge) on each of the SCL and SDA lines which means that there are 4 effective signals that can be transmitted over the pair.
Since we know that we need to be able to transmit a 0 and a 1 for binary data that leaves us with two other signals for controlling the logical state of the bus. In convention we will say that if the SDA line stays consistent for the entire period that the SCL line is high (between sequential positive and negative edges) then the state of SDA during that time will represent the 0 or 1 we are transmitting. If the SDA line changes during the period that the SCL line is high (between sequential positive and negative edges) then the direction of change in SDA (posedge for stop or negedge for start) during that time will represent the logical beginning or end of a logical set of 0's and 1's that belong together.
So, if we want to determine what signals (0,1,start,stop) exist on the bus we need to build a little detector module. This is rather straightforward in verilog - if we keep track of the previous states of sda and scl and compare them to the current states we can easily determine which of the four possible signals have occurred. When we see one of these conditions, we will set the appropriate output signal (rec_start, rec_stop, rec_data0, rec_data1) high.
Since it's important to know when the signal occurred (they only exist for a moment) we will clear the signals on the next system clock cycle.
scl_p <= scl; // remember previous state
sda_p <= sda; // remember previous state
if (scl && !scl_p) begin
// we have the positive edge of a pulse
sda_f <= sda; // remember sda state at front edge of pulse
flag <= 1'b1; // set flag - we saw the front edge
else if (!scl && scl_p && (sda_f == sda) && flag) begin
// both high or both low on neg edge of scl
rec_data0 <= !sda;
rec_data1 <= sda;
flag <= 1'b0; // reset flag
else if (scl && scl_p) begin
if (sda && !sda_p) begin
rec_stop <= 1'b1;
else if (!sda && sda_p) begin
rec_start <= 1'b1;
flag <= 1'b0;
// clear so they last only 1 cycle
if (rec_start) rec_start <= 1'b0;
if (rec_stop) rec_stop <= 1'b0;
if (rec_data0) rec_data0 <= 1'b0;
if (rec_data1) rec_data1 <= 1'b0;
here and contains the initializations, inputs and outputs for the module. Overall it's relatively simple and straightforward to implement (but simple and straightforward is often good).