1 I've rejected WISHBONE as being too low performance. Altera's Avalon
2 represents the golden standard for me, but it's _very_ general and
3 would take much effort to replicate.
5 For my needs I only need:
6 - all reads are pipelined with variable latency
14 Master raises transfer_request to initial a transfer. Slave
15 asynchronously raises wait_request when it's not ready. The master is
16 expected to hold the request and associated parameters stable until
19 Example, a master side state machine issuing two requests (no bust)
22 always @(posedge clock) case (state)
24 ... <parameters> ... <= .... params for 1st req ....
25 transfer_request <= 1;
29 S2: if (~wait_request) begin
30 ... <parameters> ... <= .... params for 1st req ....
34 S3: if (~wait_request) begin
35 transfer_request <= 0;
43 Read requests are just like write requests, except that one or more
44 cycles in the future replies will arrive, in the order issued, raising
45 data_valid for one cycle for each reply.
47 Extending the above example, we need a separate state machine
48 collecting the data as we can't assume anything about how long we will
51 always @(posedge clock) begin
53 if (waiting_for_1st) begin
54 first <= port_read_data;
57 second <= port_read_data;
63 ... <parameters> ... <= .... params for 1st req ....
64 transfer_request <= 1;
69 S2: if (~wait_request) begin
70 ... <parameters> ... <= .... params for 2nd req ....
75 S3: if (~wait_request) begin
76 transfer_request <= 0;
80 S4: if (~waiting_for_1st & ~waiting_for_2nd) begin
86 In many cases burst transfers can replace the need for multiple
93 I really like the shared based approach to arbitration that Avalon
94 has. Let's see if we can replicate it.
99 if (transfer_request_a & (shares_left_for_a | ~transfer_request_b))
100 go ahead and let A get access
101 if (shares_left_for_a == 0)
102 shares_left_for_a = A_SHARES
105 else if (transfer_request_b & (shares_left_for_b | ~transfer_request_a))
106 go ahead and let B get access
107 if (shares_left_for_b == 0)
108 shares_left_for_b = A_SHARES
111 else /* ~transfer_request_a & ~transfer_request_b */
112 shares_left_for_a = A_SHARES
113 shares_left_for_b = A_SHARES
116 Puh, not tooo complicated? Just wait until we throw burst support into the mix.
118 Also, I failed to show how to support routing the read data back to
119 theirs masters. A simple 1-bit FIFO of length A_SHARES + B_SHARES
120 (??) should be sufficient. (Careful about the latency of the FIFO
121 itself.) However, the arbitration must know which requests will
122 result in a reply. (Should simply all requests result in a reply to
129 I haven't found documentation for how Avalon handles this, but it
130 seems that simply extending the basic strategy with a burst count
133 Example: lets show the client side for a change (as the master looks
134 almost exactly the same as for a single request). This simple client
135 can only handle one outstanding request at a time, but it does support
138 wire wait_request = count != 0;
140 always @(posedge clock) begin
141 pipeline[N:1] <= pipeline[N-1:0];
147 else if (transfer_request) begin
148 count <= burst_length;
153 (Of course the counting down to -1 and using the sign bit would be
157 The only extension needed for the arbitration is knowing about the