ethernet/rtl/hub.v

212 lines
4.8 KiB
Verilog

// SPDX-License-Identifier: AGPL-3.0-Only OR CERN-OHL-S-2.0
/*
* Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
*/
`include "common.vh"
module hub (
input clk_125,
input clk_250,
input [PORT_COUNT - 1:0] indicate_data,
input [PORT_COUNT - 1:0] signal_detect,
output [PORT_COUNT - 1:0] request_data,
/* Wishbone management */
input wb_rst,
output wb_ack, wb_err,
input wb_cyc, wb_stb, wb_we,
input [PORT_COUNT + 5 - 1:0] wb_addr,
input [15:0] wb_data_write,
output [15:0] wb_data_read,
/* Other status (for LEDs) */
output reg collision, transmitting,
output [PORT_COUNT - 1:0] link_status,
output [PORT_COUNT - 1:0] receiving
);
parameter WISHBONE = 1;
parameter REGISTER_WB = 1;
parameter PORT_COUNT = 4;
parameter ELASTIC_BUF_SIZE = 5;
parameter ENABLE_COUNTERS = 1;
parameter COUNTER_WIDTH = 15;
parameter [23:0] OUI = 0;
parameter [5:0] MODEL = 0;
parameter [3:0] REVISION = 0;
localparam MII_100_RATIO = 5;
reg buf_ce, tx_ce;
wire collision_next, transmitting_next;
wire [PORT_COUNT - 1:0] rx_ce, rx_dv, rx_er, tx_en, tx_er, buf_dv, buf_er, col, crs;
wire [PORT_COUNT * 4 - 1:0] rxd, txd, buf_data;
hub_core #(
.PORT_COUNT(PORT_COUNT)
) hub (
.clk(clk_125),
.rx_dv(buf_dv),
.rx_er(buf_er),
.rxd(buf_data),
.tx_en(tx_en),
.tx_er(tx_er),
.txd(txd),
.jam(collision_next),
.activity(transmitting_next)
);
wire [PORT_COUNT - 1:0] bus_ack, bus_err, bus_cyc, bus_stb, bus_we;
wire [5 * PORT_COUNT - 1:0] bus_addr;
wire [16 * PORT_COUNT - 1:0] bus_data_write, bus_data_read;
generate if (WISHBONE) begin
wb_mux #(
.ADDR_WIDTH(5),
.DATA_WIDTH(16),
.SLAVES(PORT_COUNT)
) mux (
.m_ack(wb_ack),
.m_err(wb_err),
.m_cyc(wb_cyc),
.m_stb(wb_stb),
.m_we(wb_we),
.m_addr(wb_addr),
.m_data_write(wb_data_write),
.m_data_read(wb_data_read),
.s_ack(bus_ack),
.s_err(bus_err),
.s_cyc(bus_cyc),
.s_stb(bus_stb),
.s_we(bus_we),
.s_addr(bus_addr),
.s_data_write(bus_data_write),
.s_data_read(bus_data_read)
);
end else begin
assign wb_ack = 0;
assign wb_err = wb_cyc && wb_stb;
assign bus_cyc = {PORT_COUNT{1'b0}};
assign bus_stb = {PORT_COUNT{1'b0}};
end endgenerate
genvar i;
generate for (i = 0; i < PORT_COUNT; i = i + 1) begin : port
wire reg_ack, reg_err, reg_cyc, reg_stb, reg_we;
wire [4:0] reg_addr;
wire [15:0] reg_data_write, reg_data_read;
if (REGISTER_WB) begin
wb_reg #(
.ADDR_WIDTH(5)
) wb_reg (
.clk(clk_125),
.rst(wb_rst),
.s_ack(bus_ack[i]),
.s_err(bus_err[i]),
.s_cyc(bus_cyc[i]),
.s_stb(bus_stb[i]),
.s_we(bus_we[i]),
.s_addr(bus_addr[i * 5 +: 5]),
.s_data_write(bus_data_write[i * 16 +: 16]),
.s_data_read(bus_data_read[i * 16 +: 16]),
.m_cyc(reg_cyc),
.m_stb(reg_stb),
.m_ack(reg_ack),
.m_err(reg_err),
.m_we(reg_we),
.m_addr(reg_addr),
.m_data_write(reg_data_write),
.m_data_read(reg_data_read)
);
end else begin
assign bus_ack[i] = reg_ack;
assign bus_err[i] = reg_err;
assign reg_cyc = bus_cyc[i];
assign reg_stb = bus_stb[i];
assign reg_we = bus_we[i];
assign reg_addr = bus_addr[i * 5 +: 5];
assign reg_data_write = bus_data_write[i * 16 +: 16];
assign bus_data_read[i * 16 +: 16] = reg_data_read;
end
phy_internal #(
.WISHBONE(WISHBONE),
.ENABLE_COUNTERS(ENABLE_COUNTERS),
.COUNTER_WIDTH(COUNTER_WIDTH),
.OUI(OUI),
.MODEL(MODEL),
.REVISION(REVISION)
) phy (
.clk_125(clk_125),
.clk_250(clk_250),
.indicate_data(indicate_data[i]),
.signal_detect(signal_detect[i]),
.request_data(request_data[i]),
.mii_tx_ce(tx_ce),
.mii_tx_en(tx_en[i]),
.mii_tx_er(tx_er[i]),
.mii_txd(txd[i * 4 +: 4]),
.mii_rx_ce(rx_ce[i]),
.mii_rx_dv(rx_dv[i]),
.mii_rx_er(rx_er[i]),
.mii_rxd(rxd[i * 4 +: 4]),
.wb_ack(reg_ack),
.wb_err(reg_err),
.wb_cyc(reg_cyc),
.wb_stb(reg_stb),
.wb_we(reg_we),
.wb_addr(reg_addr),
.wb_data_write(reg_data_write),
.wb_data_read(reg_data_read),
.link_status(link_status[i]),
.receiving(receiving[i])
);
mii_elastic_buffer #(
.BUF_SIZE(ELASTIC_BUF_SIZE)
) buffer (
.clk(clk_125),
.tx_ce(rx_ce[i]),
.tx_en(rx_dv[i]),
.tx_er(rx_er[i]),
.txd(rxd[i * 4 +: 4]),
.rx_ce(buf_ce),
.rx_dv(buf_dv[i]),
.rx_er(buf_er[i]),
.rxd(buf_data[i * 4 +: 4])
);
end endgenerate
reg buf_ce_next;
reg [3:0] tx_counter, tx_counter_next;
initial begin
buf_ce = 0;
tx_ce = 0;
tx_counter = MII_100_RATIO - 1;
end
always @(*) begin
buf_ce_next = 0;
tx_counter_next = tx_counter - 1;
if (!tx_counter) begin
tx_counter_next = MII_100_RATIO - 1;
buf_ce_next = 1;
end
end
always @(posedge clk_125) begin
buf_ce <= buf_ce_next;
tx_ce <= buf_ce;
tx_counter <= tx_counter_next;
if (tx_ce) begin
collision <= collision_next;
transmitting <= transmitting_next;
end
end
endmodule