媒体无关接口模块提供一个连接到外部以太网 PHY 控制器的接口,用来设置 PHY 控制器的寄存器并获得其状态信息,如图 10-8 所示。
媒体无关接口模块包括以下 3 个子模块和控制逻辑。
• 时钟产生模块:产生 MII 接口的时钟信号,这个时钟信号需要满足外部 PHY 芯片对时钟的要求。
• 输出控制模块:因为 MII 连接到外部 PHY 的数据线实际只有一根线,输出控制模块需要将输出、输入和使能信号联合形成一个信号。
• 移位寄存器模块:将需要传输到外部 PHY 芯片的数据串行化,同时将从外部 PHY 芯片接收的串行数据并行保存到寄存器中。
• 控制逻辑:实现读、写和查找等请求信号的同步,提供输入数据的锁存信号,提供移位输出数据的字节选择信号,提供 MII 的计数器,提供更新相关寄存器的信号。
下面是媒体无关接口模块的主要代码:
- `include "timescale.v"
- module eth_miim
- ( Clk, Reset, Divider, NoPre, CtrlData, Rgad, Fiad, WCtrlData, RStat, ScanStat,Mdi,
- Mdo, MdoEn, Mdc, Busy, Prsd, LinkFail, Nvalid, WCtrlDataStart, RStatStart,UpdateMIIRX_DATAReg );
- //输出输入信号
- input Clk; //主时钟
- input Reset; // 复位信号
- input [7:0] Divider; // 主时钟的分频参数
- input [15:0] CtrlData; //写到外部 PHY 芯片寄存器的控制数据
- input [4:0] Rgad; // 外部 PHY 芯片寄存器的地址
- input [4:0] Fiad; // PHY 的地址
- input NoPre; // 无报头
- input WCtrlData; // 写控制数据操作
- input RStat; // 读状态操作
- input ScanStat; // 查找状态操作
- input Mdi; // MII 数据输入
- output Mdc; // MII 数据时钟
- output Mdo; // MII 数据输入
- output MdoEn; // MII 数据输出使能信号
- output Busy; // 忙信号
- output LinkFail; // 连接整体信号
- output Nvalid; // 非法状态
- output [15:0] Prsd; // 从外部 PHY 芯片读取状态数据
- output WCtrlDataStart; // 复位 MII 命令寄存器中 WCTRLDATA 位的信号
- output RStatStart; // 复位 MII 命令寄存器中 RSTAT 位的信号
- output UpdateMIIRX_DATAReg;//用读数据来更新 MII 的 RX_DATA 寄存器
- parameter Tp = 1;
- //寄存器
- reg Nvalid;
- ………
- //产生结束忙信号,用来结束 MII 操作
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- begin
- EndBusy_d <= #Tp 1'b0;
- EndBusy <= #Tp 1'b0;
- end
- else
- begin
- EndBusy_d <= #Tp ~InProgress_q2 & InProgress_q3;
- EndBusy <= #Tp EndBusy_d;
- end
- end
- // 更新 MII 的 RX_DATA 寄存器
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- UpdateMIIRX_DATAReg <= #Tp 0;
- else
- if(EndBusy & ~WCtrlDataStart_q)
- UpdateMIIRX_DATAReg <= #Tp 1;
- else
- UpdateMIIRX_DATAReg <= #Tp 0;
- end
- //产生延迟信号
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- begin
- WCtrlData_q1 <= #Tp 1'b0;
- WCtrlData_q2 <= #Tp 1'b0;
- WCtrlData_q3 <= #Tp 1'b0;
- RStat_q1 <= #Tp 1'b0;
- RStat_q2 <= #Tp 1'b0;
- RStat_q3 <= #Tp 1'b0;
- ScanStat_q1 <= #Tp 1'b0;
- ScanStat_q2 <= #Tp 1'b0;
- SyncStatMdcEn <= #Tp 1'b0;
- end
- else
- begin
- WCtrlData_q1 <= #Tp WCtrlData;
- WCtrlData_q2 <= #Tp WCtrlData_q1;
- WCtrlData_q3 <= #Tp WCtrlData_q2;
- RStat_q1 <= #Tp RStat;
- RStat_q2 <= #Tp RStat_q1;
- RStat_q3 <= #Tp RStat_q2;
- ScanStat_q1 <= #Tp ScanStat;
- ScanStat_q2 <= #Tp ScanStat_q1;
- if(MdcEn)
- SyncStatMdcEn <= #Tp ScanStat_q2;
- end
- end
- //产生开始命令,写控制数据或者读状态
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- begin
- WCtrlDataStart <= #Tp 1'b0;
- WCtrlDataStart_q <= #Tp 1'b0;
- RStatStart <= #Tp 1'b0;
- end
- else
- begin
- if(EndBusy)
- begin
- WCtrlDataStart <= #Tp 1'b0;
- RStatStart <= #Tp 1'b0;
- end
- else
- begin
- if(WCtrlData_q2 & ~WCtrlData_q3)
- WCtrlDataStart <= #Tp 1'b1;
- if(RStat_q2 & ~RStat_q3)
- RStatStart <= #Tp 1'b1;
- WCtrlDataStart_q <= #Tp WCtrlDataStart;
- end
- end
- end
- // 产生非法信号,指示当前状态非法
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- Nvalid <= #Tp 1'b0;
- else
- begin
- if(~InProgress_q2 & InProgress_q3)
- begin
- Nvalid <= #Tp 1'b0;
- end
- else
- begin
- if(ScanStat_q2 & ~SyncStatMdcEn)
- Nvalid <= #Tp 1'b1;
- end
- end
- end
- // 用来产生各种操作的信号
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- begin
- WCtrlDataStart_q1 <= #Tp 1'b0;
- WCtrlDataStart_q2 <= #Tp 1'b0;
- RStatStart_q1 <= #Tp 1'b0;
- RStatStart_q2 <= #Tp 1'b0;
- InProgress_q1 <= #Tp 1'b0;
- InProgress_q2 <= #Tp 1'b0;
- InProgress_q3 <= #Tp 1'b0;
- LatchByte0_d <= #Tp 1'b0;
- LatchByte1_d <= #Tp 1'b0;
- LatchByte <= #Tp 2'b00;
- end
- else
- begin
- if(MdcEn)
- begin
- WCtrlDataStart_q1 <= #Tp WCtrlDataStart;
- WCtrlDataStart_q2 <= #Tp WCtrlDataStart_q1;
- RStatStart_q1 <= #Tp RStatStart;
- RStatStart_q2 <= #Tp RStatStart_q1;
- LatchByte[0] <= #Tp LatchByte0_d;
- LatchByte[1] <= #Tp LatchByte1_d;
- LatchByte0_d <= #Tp LatchByte0_d2;
- LatchByte1_d <= #Tp LatchByte1_d2;
- InProgress_q1 <= #Tp InProgress;
- InProgress_q2 <= #Tp InProgress_q1;
- InProgress_q3 <= #Tp InProgress_q2;
- end
- end
- end
- // 产生各种操作信号
- assign WriteDataOp = WCtrlDataStart_q1 & ~WCtrlDataStart_q2;
- assign ReadStatusOp = RStatStart_q1 & ~RStatStart_q2;
- assign ScanStatusOp = SyncStatMdcEn & ~InProgress & ~InProgress_q1 & ~InProgress_q2;
- assign StartOp = WriteDataOp | ReadStatusOp | ScanStatusOp;
- // 忙信号
- assign Busy = WCtrlDataStart | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3
- | Nvalid;
- // 产生进行中信号,指示当前操作正在进行
- // 产生写操作信号,指示写数据正在进行
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- begin
- InProgress <= #Tp 1'b0;
- WriteOp <= #Tp 1'b0;
- end
- else
- begin
- if(MdcEn)
- begin
- if(StartOp)
- begin
- if(~InProgress)
- WriteOp <= #Tp WriteDataOp;
- InProgress <= #Tp 1'b1;
- end
- else
- begin
- if(EndOp)
- begin
- InProgress <= #Tp 1'b0;
- WriteOp <= #Tp 1'b0;
- end
- end
- end
- end
- end
- // 位计数器
- always @ (posedge Clk or posedge Reset)
- begin
- if(Reset)
- BitCounter[6:0] <= #Tp 7'h0;
- else
- begin
- if(MdcEn)
- begin
- if(InProgress)
- begin
- if(NoPre & ( BitCounter == 7'h0 ))
- BitCounter[6:0] <= #Tp 7'h21;
- else
- BitCounter[6:0] <= #Tp BitCounter[6:0] + 1'b1;
- end
- else
- BitCounter[6:0] <= #Tp 7'h0;
- end
- end
- end
- // 当计数器达到 63 时结束操作
- assign EndOp = BitCounter==63;
- assign ByteSelect[0] = InProgress & ((NoPre & (BitCounter == 7'h0)) | (~NoPre & (BitCounter
- == 7'h20)));
- assign ByteSelect[1] = InProgress & (BitCounter == 7'h28);
- assign ByteSelect[2] = InProgress & WriteOp & (BitCounter == 7'h30);
- assign ByteSelect[3] = InProgress & WriteOp & (BitCounter == 7'h38);
- //当从移位寄存器中读取状态数据时锁存字节选择信号
- assign LatchByte1_d2 = InProgress & ~WriteOp & BitCounter == 7'h37;
- assign LatchByte0_d2 = InProgress & ~WriteOp & BitCounter == 7'h3F;
- //连接时钟产生模块
- eth_clockgen
- clkgen(.Clk(Clk), .Reset(Reset), .Divider(Divider[7:0]), .MdcEn(MdcEn), .MdcEn_n(MdcEn_n), .Mdc(Mdc)
- );
- // 连接移位寄存器模块
- eth_shiftreg
- shftrg(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .Mdi(Mdi), .Fiad(Fiad), .Rgad(Rgad),
- .CtrlData(CtrlData), .WriteOp(WriteOp), .ByteSelect(ByteSelect), .LatchByte(LatchByte),
- .ShiftedBit(ShiftedBit), .Prsd(Prsd), .LinkFail(LinkFail)
- );
- // 连接输出控制模块
- eth_outputcontrol
- outctrl(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .InProgress(InProgress),
- .ShiftedBit(ShiftedBit), .BitCounter(BitCounter), .WriteOp(WriteOp), .NoPre(NoPre),
- .Mdo(Mdo), .MdoEn(MdoEn)
- );
- endmodule