Sylvain Munaut | 21b03ba | 2020-09-14 10:01:45 +0200 | [diff] [blame] | 1 | /* |
| 2 | * wb_arbiter.v |
| 3 | * |
| 4 | * vim: ts=4 sw=4 |
| 5 | * |
| 6 | * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com> |
| 7 | * SPDX-License-Identifier: CERN-OHL-P-2.0 |
| 8 | */ |
| 9 | |
| 10 | `default_nettype none |
| 11 | |
| 12 | module wb_arbiter #( |
| 13 | parameter integer N = 3, |
| 14 | parameter integer DW = 32, |
| 15 | parameter integer AW = 16, |
| 16 | parameter integer MW = DW / 8 |
| 17 | )( |
| 18 | /* Slave buses */ |
| 19 | input wire [(N*AW)-1:0] s_addr, |
| 20 | output wire [(N*DW)-1:0] s_rdata, |
| 21 | input wire [(N*DW)-1:0] s_wdata, |
| 22 | input wire [(N*MW)-1:0] s_wmsk, |
| 23 | input wire [ N -1:0] s_we, |
| 24 | input wire [ N -1:0] s_cyc, |
| 25 | output wire [ N -1:0] s_ack, |
| 26 | |
| 27 | /* Master bus */ |
| 28 | output reg [AW-1:0] m_addr, |
| 29 | input wire [DW-1:0] m_rdata, |
| 30 | output reg [DW-1:0] m_wdata, |
| 31 | output reg [MW-1:0] m_wmsk, |
| 32 | output reg m_we, |
| 33 | output wire m_cyc, |
| 34 | input wire m_ack, |
| 35 | |
| 36 | /* Clock / Reset */ |
| 37 | input wire clk, |
| 38 | input wire rst |
| 39 | ); |
| 40 | |
| 41 | // Signals |
| 42 | // ------- |
| 43 | |
| 44 | genvar i; |
| 45 | |
| 46 | reg [AW-1:0] mux_addr; |
| 47 | reg [DW-1:0] mux_wdata; |
| 48 | reg [MW-1:0] mux_wmsk; |
| 49 | |
| 50 | reg [N-1:0] sel_nxt; |
| 51 | reg [N-1:0] sel; |
| 52 | reg busy; |
| 53 | wire reselect; |
| 54 | |
| 55 | |
| 56 | // Muxing |
| 57 | // ------ |
| 58 | |
| 59 | for (i=0; i<N; i=i+1) |
| 60 | begin |
| 61 | assign s_rdata[DW*i+:DW] = sel[i] ? m_rdata : { DW{1'b0} }; |
| 62 | assign s_ack[i] = sel[i] ? m_ack : 1'b0; |
| 63 | end |
| 64 | |
| 65 | always @(*) |
| 66 | begin : mux |
| 67 | integer i; |
| 68 | |
| 69 | mux_addr = { AW{1'b0} }; |
| 70 | mux_wdata = { DW{1'b0} }; |
| 71 | mux_wmsk = { MW{1'b0} }; |
| 72 | |
| 73 | for (i=N-1; i>=0; i=i-1) begin |
| 74 | mux_addr = mux_addr | (sel_nxt[i] ? s_addr[AW*i+:AW] : { AW{1'b0} }); |
| 75 | mux_wdata = mux_wdata | (sel_nxt[i] ? s_wdata[DW*i+:DW] : { DW{1'b0} }); |
| 76 | mux_wmsk = mux_wmsk | (sel_nxt[i] ? s_wmsk[MW*i+:MW] : { MW{1'b0} }); |
| 77 | end |
| 78 | end |
| 79 | |
| 80 | always @(posedge clk or posedge rst) |
| 81 | begin |
| 82 | if (rst) begin |
| 83 | m_addr <= { AW{1'b0} }; |
| 84 | m_wdata <= { DW{1'b0} }; |
| 85 | m_wmsk <= { MW{1'b0} }; |
| 86 | m_we <= 1'b0; |
| 87 | end else if (reselect) begin |
| 88 | m_addr <= mux_addr; |
| 89 | m_wdata <= mux_wdata; |
| 90 | m_wmsk <= mux_wmsk; |
| 91 | m_we <= |(s_we & sel_nxt); |
| 92 | end |
| 93 | end |
| 94 | |
| 95 | |
| 96 | // Arbitration |
| 97 | // ----------- |
| 98 | |
| 99 | // Priority encoder for the next master |
| 100 | always @(*) |
| 101 | begin : prio |
| 102 | integer i; |
| 103 | |
| 104 | sel_nxt <= 0; |
| 105 | for (i=N-1; i>=0; i=i-1) |
| 106 | if (s_cyc[i] & ~sel[i]) begin |
| 107 | sel_nxt <= 0; |
| 108 | sel_nxt[i] <= 1'b1; |
| 109 | end |
| 110 | end |
| 111 | |
| 112 | // When to reselect |
| 113 | assign reselect = m_ack | ~busy; |
| 114 | |
| 115 | // Register current master (if any) |
| 116 | always @(posedge clk or posedge rst) |
| 117 | if (rst) begin |
| 118 | busy <= 1'b0; |
| 119 | sel <= 0; |
| 120 | end else if (reselect) begin |
| 121 | busy <= |(s_cyc & ~sel); |
| 122 | sel <= sel_nxt; |
| 123 | end |
| 124 | |
| 125 | assign m_cyc = busy; |
| 126 | |
| 127 | endmodule // wb_arbiter |