98 lines
3.5 KiB
Systemverilog
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
|