/* * mdio_cont.v * * Copyright (C) 2018, 2019 Mind Chasers Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * function: MDIO controller / state machine * */ `timescale 1ns /10ps module mdio_controller #(parameter ADDR_SZ = 6) ( // system interface input rstn, input clk, // mdio mdc clock // worker interface input work_start, output reg work_run, output reg work_done, input [ADDR_SZ-1:0] routine_addr, // arbitration input buffer_full, // memory interface output reg [ADDR_SZ-1:0] addr, // controller address input [7:0] di, // controller data bus // mdio interface output reg [4:0] reg_addr, output reg [15:0] dout, // data output ( for writes ) output ld, // load control / address, output reg rwn, // read / write not input done ); localparam ST_SZ = 4; reg [ST_SZ-1:0] cont_state; wire ld_dl, ld_dh; // state encoding localparam S0= 4'h0, S1=4'h1, S2=4'h2, S3=4'h3, S4= 4'h4, S5=4'h5, S6=4'h6, S7=4'h7, S8 = 4'h8; /* * keep running until an eop is found */ always @(posedge clk or negedge rstn) begin if (!rstn) cont_state <= S0; else case (cont_state) S0: if (work_start == 1'b1) cont_state <= S1; S1: cont_state <= S2; S2: if ( work_done == 1'b1 ) cont_state <= S0; else if ( buffer_full ) cont_state <= S2; // wait for the fifo to empty out else if ( ~rwn ) cont_state <= S3; else cont_state <= S6; S3: cont_state <= S4; S4: cont_state <= S5; S5: cont_state <= S6; S6: cont_state <= S7; S7: if ( done == 1'b1 ) cont_state <= S8; S8: cont_state <= S1; endcase end /* read the eop bit during S1 */ always @(posedge clk or negedge rstn) begin if ( !rstn ) work_done <= 1'b0; else if ( cont_state == S1 && di[7] == 1'b1 ) work_done <= 1'b1; else work_done <= 1'b0; end /* work_run */ always @(posedge clk or negedge rstn) begin if ( !rstn ) work_run <= 1'b0; else if ( work_start == 1'b1 ) work_run <= 1'b1; else if ( work_done == 1'b1 ) work_run <= 1'b0; end /* set RWN for duration of cyle */ always @(posedge clk or negedge rstn) begin if ( rstn == 1'b0 || work_done ==1'b1 ) begin rwn <= 1'b1; end else if ( cont_state == S1 ) begin rwn <= di[5]; end end /* reg_addr is the mdio register address */ always @(posedge clk or negedge rstn) begin if ( rstn == 1'b0 || work_done ==1'b1 ) reg_addr <= 5'h0; else if ( cont_state == S1 ) reg_addr <= di[4:0]; end /* addr is the program address */ always @(posedge clk or negedge rstn) begin if (rstn == 1'b0 || work_done == 1'b1 ) addr <= 0; else if ( work_start == 1'b1 ) addr <= routine_addr[ADDR_SZ-1:0]; else if ( cont_state == S3 || cont_state == S4 || cont_state == S8 ) addr <= addr + 1; end // latch the write data to mdio always @(posedge clk or negedge rstn) begin if (rstn == 0) dout <= 16'h0000; else if ( ld_dl == 1'b1 ) dout[7:0] <= di; else if ( ld_dh == 1'b1 ) dout[15:8] <= di; end // combinatorial logic here assign ld_dl = ( cont_state == S4 ) ? 1'b1 : 1'b0; assign ld_dh = ( cont_state == S5 ) ? 1'b1 : 1'b0; assign ld = ( cont_state == S6 ) ? 1'b1 : 1'b0; endmodule