Files
max2771-raw-ethernet-recorder/rtl/common/mdio_master.sv
T

98 lines
3.5 KiB
Systemverilog

`default_nettype none
// IEEE 802.3 Clause-22 management interface. MDC is stopped low between
// commands. A read releases MDIO for both turnaround bits and all data bits.
module mdio_master #(
parameter int unsigned MDC_DIV = 25
) (
input wire logic clk,
input wire logic rst,
input wire logic start,
input wire logic command_write,
input wire logic [4:0] phy_address,
input wire logic [4:0] register_address,
input wire logic [15:0] write_data,
output logic busy,
output logic done,
output logic [15:0] read_data,
output logic read_valid,
output logic mdc,
input wire logic mdio_i,
output logic mdio_o,
output logic mdio_oe
);
localparam int unsigned DIV_W = (MDC_DIV < 2) ? 1 : $clog2(MDC_DIV);
logic [DIV_W-1:0] div_count;
logic [5:0] bit_index;
logic [63:0] frame_bits;
logic [15:0] read_shift;
logic read_command_q;
initial begin
if (MDC_DIV < 2) $error("MDC_DIV must be at least two");
end
always_comb begin
mdio_o = frame_bits[bit_index];
mdio_oe = busy;
if (busy && read_command_q && bit_index <= 6'd17)
mdio_oe = 1'b0;
end
always_ff @(posedge clk) begin
if (rst) begin
busy <= 1'b0;
done <= 1'b0;
read_valid <= 1'b0;
read_data <= 16'd0;
read_shift <= 16'd0;
mdc <= 1'b0;
div_count <= '0;
bit_index <= 6'd63;
frame_bits <= 64'hffffffff_6000_0000;
read_command_q <= 1'b0;
end else begin
done <= 1'b0;
read_valid <= 1'b0;
if (!busy) begin
mdc <= 1'b0;
div_count <= '0;
if (start) begin
busy <= 1'b1;
bit_index <= 6'd63;
read_shift <= 16'd0;
read_command_q <= !command_write;
frame_bits[63:32] <= 32'hffffffff;
frame_bits[31:30] <= 2'b01;
frame_bits[29:28] <= command_write ? 2'b01 : 2'b10;
frame_bits[27:23] <= phy_address;
frame_bits[22:18] <= register_address;
frame_bits[17:16] <= 2'b10;
frame_bits[15:0] <= write_data;
end
end else if (div_count == MDC_DIV-1) begin
div_count <= '0;
if (!mdc) begin
// Rising MDC: PHY sources read data; master samples it.
mdc <= 1'b1;
if (read_command_q && bit_index <= 6'd15)
read_shift <= {read_shift[14:0], mdio_i};
end else begin
// Falling MDC: move to the next bit or finish the command.
mdc <= 1'b0;
if (bit_index == 6'd0) begin
busy <= 1'b0;
done <= 1'b1;
if (read_command_q) begin
read_data <= read_shift;
read_valid <= 1'b1;
end
end else bit_index <= bit_index - 6'd1;
end
end else div_count <= div_count + {{(DIV_W-1){1'b0}},1'b1};
end
end
endmodule
`default_nettype wire