Question

I'm finishing up a project and a requirement is two-way handshaking between functional units inside our processor. I know what it is but is there any 'standard' or a good simple example of it?

Only thing I can think of between two units, when there's a data-line between them and when X sends to Y, a separate 'sent' signal is given. When Y receives a 'received' signal is sent to X on another wire. Once X reads that received signal it stops sending data on the data-line and sets sent wire to 0 or Z. Y then sets received signal to 0 or Z as well.

This is all synchronous (on the same clock).

Is this a valid way to go about this? I figure it can get very messy on a large scale but I'm only working on a simple accumulator based processor.

Était-ce utile?

La solution

The most common simple handshake for a single clock domain would be the valid/ready handshake.

If 'X' is sending to 'Y', then X has outputs of data and valid, and Y has an output of ready.

When X has data to send, it asserts valid, and looks at ready. If valid and ready are high on posedge clock, then X will consider the data to be sent, and Y will consider the data to be received.

The advantage of this scheme is that you can send one data per clock cycle without any down time. If valid is still high the next cycle after valid/ready was high, then this is considered a second packet.

Also there is no requirement that Y waits to see valid before it asserts ready, Y can assert ready anytime it is available to receive a data.

The scheme you describe is what I would call a 'req/ack 4-phase handshake', in that it takes four clock cycles to send one data

1. req=1 ack=0
2. req=1 ack=1
3. req=0 ack=1
4. req=0 ack=0

This kind of interface would be better when doing an asynchronous request across a clock boundary, as it eliminates any possibility of interpreting a packet twice. But you don't need this for a fully synchronous interface.

Autres conseils

I often use schemes similar to Tims suggestion for having FSMs triggering/pausing each other. The go (req) signal may trigger a processing in a lower or secondary module which acknowledges when it has completed.

reg go;
reg complete;

//abstracted FSM1
always @(posedge clk) begin
  case( fsm1_state )
    START_SUB : begin
      go              <= 1'b1;
      fsm1_next_state <= WAIT_SUB;
    end
    WAIT_SUB: begin
      if (complete == 1'b1) begin
        go              <= 1'b0;
        fsm1_next_state <= COMPLETED_SUB;
      end
      else begin
        go              <= 1'b1;         //Might not be required to hold high in Synch design
        fsm1_next_state <= WAIT_SUB;     // Holds state
      end
    end
    default: begin
      go              <= 1'b0;
      fsm1_next_state <= fsm1_state;
    end
  endcase
end

//fsm2
always @(posedge clk) begin
  case( fsm2_state )
    WAITING : begin
      complete        <= 1'b0;
      if (go ==1'b1) begin
        fsm2_next_state <= DOSOMETHING;
      end
      else begin
        fsm2_next_state <= WAITING;
      end 
    end
    DOSOMETHING : begin
      complete        <= 1'b1;
      fsm2_next_state <= WAITING;
      // if an async system wait until go is deasserted
      // rather than pulse complete for 1 cycle
    end
  endcase
end

State machines should always be initialised or reset and use a default case to remove unintentional lockout states.

I think you're looking to design an Arbiter. There are many different arbitration schemes. The simplest is a round-robin scheme. If anyone wants access to a resource (like the CPU or a memory etc) then that module would assert a request line. It waits until the arbiter asserts a grant line, at which point it is allowed to continue its processing knowing that it has dedicated access to the interface that is being controlled by the arbiter.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top