FPGA 学习小组
直播中

alexdos

6年用户 804经验值
擅长:可编程逻辑 电源/新能源 嵌入式技术 模拟技术
私信 关注

以太网控制器媒体无关接口模块实现代码

媒体无关接口模块提供一个连接到外部以太网 PHY 控制器的接口,用来设置 PHY 控制器的寄存器并获得其状态信息,如图 10-8 所示。
6.jpg
媒体无关接口模块包括以下 3 个子模块和控制逻辑。

• 时钟产生模块:产生 MII 接口的时钟信号,这个时钟信号需要满足外部 PHY 芯片对时钟的要求。

• 输出控制模块:因为 MII 连接到外部 PHY 的数据线实际只有一根线,输出控制模块需要将输出、输入和使能信号联合形成一个信号。

• 移位寄存器模块:将需要传输到外部 PHY 芯片的数据串行化,同时将从外部 PHY 芯片接收的串行数据并行保存到寄存器中。

• 控制逻辑:实现读、写和查找等请求信号的同步,提供输入数据的锁存信号,提供移位输出数据的字节选择信号,提供 MII 的计数器,提供更新相关寄存器的信号。

下面是媒体无关接口模块的主要代码:

  1. `include "timescale.v"
  2. module eth_miim
  3. ( Clk, Reset, Divider, NoPre, CtrlData, Rgad, Fiad, WCtrlData, RStat, ScanStat,Mdi,
  4. Mdo, MdoEn, Mdc, Busy, Prsd, LinkFail, Nvalid, WCtrlDataStart, RStatStart,UpdateMIIRX_DATAReg );
  5. //输出输入信号
  6. input Clk; //主时钟
  7. input Reset; // 复位信号
  8. input [7:0] Divider; // 主时钟的分频参数
  9. input [15:0] CtrlData; //写到外部 PHY 芯片寄存器的控制数据
  10. input [4:0] Rgad; // 外部 PHY 芯片寄存器的地址
  11. input [4:0] Fiad; // PHY 的地址
  12. input NoPre; // 无报头
  13. input WCtrlData; // 写控制数据操作
  14. input RStat; // 读状态操作
  15. input ScanStat; // 查找状态操作
  16. input Mdi; // MII 数据输入
  17. output Mdc; // MII 数据时钟
  18. output Mdo; // MII 数据输入
  19. output MdoEn; // MII 数据输出使能信号
  20. output Busy; // 忙信号
  21. output LinkFail; // 连接整体信号
  22. output Nvalid; // 非法状态
  23. output [15:0] Prsd; // 从外部 PHY 芯片读取状态数据
  24. output WCtrlDataStart; // 复位 MII 命令寄存器中 WCTRLDATA 位的信号
  25. output RStatStart; // 复位 MII 命令寄存器中 RSTAT 位的信号
  26. output UpdateMIIRX_DATAReg;//用读数据来更新 MII 的 RX_DATA 寄存器
  27. parameter Tp = 1;
  28. //寄存器
  29. reg Nvalid;
  30. ………
  31. //产生结束忙信号,用来结束 MII 操作
  32. always @ (posedge Clk or posedge Reset)
  33. begin
  34. if(Reset)
  35. begin
  36. EndBusy_d <= #Tp 1'b0;
  37. EndBusy <= #Tp 1'b0;
  38. end
  39. else
  40. begin
  41. EndBusy_d <= #Tp ~InProgress_q2 & InProgress_q3;
  42. EndBusy <= #Tp EndBusy_d;
  43. end
  44. end
  45. // 更新 MII 的 RX_DATA 寄存器
  46. always @ (posedge Clk or posedge Reset)
  47. begin
  48. if(Reset)
  49. UpdateMIIRX_DATAReg <= #Tp 0;
  50. else
  51. if(EndBusy & ~WCtrlDataStart_q)
  52. UpdateMIIRX_DATAReg <= #Tp 1;
  53. else
  54. UpdateMIIRX_DATAReg <= #Tp 0;
  55. end
  56. //产生延迟信号
  57. always @ (posedge Clk or posedge Reset)
  58. begin
  59. if(Reset)
  60. begin
  61. WCtrlData_q1 <= #Tp 1'b0;
  62. WCtrlData_q2 <= #Tp 1'b0;
  63. WCtrlData_q3 <= #Tp 1'b0;
  64. RStat_q1 <= #Tp 1'b0;
  65. RStat_q2 <= #Tp 1'b0;
  66. RStat_q3 <= #Tp 1'b0;
  67. ScanStat_q1 <= #Tp 1'b0;
  68. ScanStat_q2 <= #Tp 1'b0;
  69. SyncStatMdcEn <= #Tp 1'b0;
  70. end
  71. else
  72. begin
  73. WCtrlData_q1 <= #Tp WCtrlData;
  74. WCtrlData_q2 <= #Tp WCtrlData_q1;
  75. WCtrlData_q3 <= #Tp WCtrlData_q2;
  76. RStat_q1 <= #Tp RStat;
  77. RStat_q2 <= #Tp RStat_q1;
  78. RStat_q3 <= #Tp RStat_q2;
  79. ScanStat_q1 <= #Tp ScanStat;
  80. ScanStat_q2 <= #Tp ScanStat_q1;
  81. if(MdcEn)
  82. SyncStatMdcEn <= #Tp ScanStat_q2;
  83. end
  84. end
  85. //产生开始命令,写控制数据或者读状态
  86. always @ (posedge Clk or posedge Reset)
  87. begin
  88. if(Reset)
  89. begin
  90. WCtrlDataStart <= #Tp 1'b0;
  91. WCtrlDataStart_q <= #Tp 1'b0;
  92. RStatStart <= #Tp 1'b0;
  93. end
  94. else
  95. begin
  96. if(EndBusy)
  97. begin
  98. WCtrlDataStart <= #Tp 1'b0;
  99. RStatStart <= #Tp 1'b0;
  100. end
  101. else
  102. begin
  103. if(WCtrlData_q2 & ~WCtrlData_q3)
  104. WCtrlDataStart <= #Tp 1'b1;
  105. if(RStat_q2 & ~RStat_q3)
  106. RStatStart <= #Tp 1'b1;
  107. WCtrlDataStart_q <= #Tp WCtrlDataStart;
  108. end
  109. end
  110. end
  111. // 产生非法信号,指示当前状态非法
  112. always @ (posedge Clk or posedge Reset)
  113. begin
  114. if(Reset)
  115. Nvalid <= #Tp 1'b0;
  116. else
  117. begin
  118. if(~InProgress_q2 & InProgress_q3)
  119. begin
  120. Nvalid <= #Tp 1'b0;
  121. end
  122. else
  123. begin
  124. if(ScanStat_q2 & ~SyncStatMdcEn)
  125. Nvalid <= #Tp 1'b1;
  126. end
  127. end
  128. end
  129. // 用来产生各种操作的信号
  130. always @ (posedge Clk or posedge Reset)
  131. begin
  132. if(Reset)
  133. begin
  134. WCtrlDataStart_q1 <= #Tp 1'b0;
  135. WCtrlDataStart_q2 <= #Tp 1'b0;
  136. RStatStart_q1 <= #Tp 1'b0;
  137. RStatStart_q2 <= #Tp 1'b0;
  138. InProgress_q1 <= #Tp 1'b0;
  139. InProgress_q2 <= #Tp 1'b0;
  140. InProgress_q3 <= #Tp 1'b0;
  141. LatchByte0_d <= #Tp 1'b0;
  142. LatchByte1_d <= #Tp 1'b0;
  143. LatchByte <= #Tp 2'b00;
  144. end
  145. else
  146. begin
  147. if(MdcEn)
  148. begin
  149. WCtrlDataStart_q1 <= #Tp WCtrlDataStart;
  150. WCtrlDataStart_q2 <= #Tp WCtrlDataStart_q1;
  151. RStatStart_q1 <= #Tp RStatStart;
  152. RStatStart_q2 <= #Tp RStatStart_q1;
  153. LatchByte[0] <= #Tp LatchByte0_d;
  154. LatchByte[1] <= #Tp LatchByte1_d;
  155. LatchByte0_d <= #Tp LatchByte0_d2;
  156. LatchByte1_d <= #Tp LatchByte1_d2;
  157. InProgress_q1 <= #Tp InProgress;
  158. InProgress_q2 <= #Tp InProgress_q1;
  159. InProgress_q3 <= #Tp InProgress_q2;
  160. end
  161. end
  162. end
  163. // 产生各种操作信号
  164. assign WriteDataOp = WCtrlDataStart_q1 & ~WCtrlDataStart_q2;
  165. assign ReadStatusOp = RStatStart_q1 & ~RStatStart_q2;
  166. assign ScanStatusOp = SyncStatMdcEn & ~InProgress & ~InProgress_q1 & ~InProgress_q2;
  167. assign StartOp = WriteDataOp | ReadStatusOp | ScanStatusOp;
  168. // 忙信号
  169. assign Busy = WCtrlDataStart | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3
  170. | Nvalid;
  171. // 产生进行中信号,指示当前操作正在进行
  172. // 产生写操作信号,指示写数据正在进行
  173. always @ (posedge Clk or posedge Reset)
  174. begin
  175. if(Reset)
  176. begin
  177. InProgress <= #Tp 1'b0;
  178. WriteOp <= #Tp 1'b0;
  179. end
  180. else
  181. begin
  182. if(MdcEn)
  183. begin
  184. if(StartOp)
  185. begin
  186. if(~InProgress)
  187. WriteOp <= #Tp WriteDataOp;
  188. InProgress <= #Tp 1'b1;
  189. end
  190. else
  191. begin
  192. if(EndOp)
  193. begin
  194. InProgress <= #Tp 1'b0;
  195. WriteOp <= #Tp 1'b0;
  196. end
  197. end
  198. end
  199. end
  200. end
  201. // 位计数器
  202. always @ (posedge Clk or posedge Reset)
  203. begin
  204. if(Reset)
  205. BitCounter[6:0] <= #Tp 7'h0;
  206. else
  207. begin
  208. if(MdcEn)
  209. begin
  210. if(InProgress)
  211. begin
  212. if(NoPre & ( BitCounter == 7'h0 ))
  213. BitCounter[6:0] <= #Tp 7'h21;
  214. else
  215. BitCounter[6:0] <= #Tp BitCounter[6:0] + 1'b1;
  216. end
  217. else
  218. BitCounter[6:0] <= #Tp 7'h0;
  219. end
  220. end
  221. end
  222. // 当计数器达到 63 时结束操作
  223. assign EndOp = BitCounter==63;
  224. assign ByteSelect[0] = InProgress & ((NoPre & (BitCounter == 7'h0)) | (~NoPre & (BitCounter
  225. == 7'h20)));
  226. assign ByteSelect[1] = InProgress & (BitCounter == 7'h28);
  227. assign ByteSelect[2] = InProgress & WriteOp & (BitCounter == 7'h30);
  228. assign ByteSelect[3] = InProgress & WriteOp & (BitCounter == 7'h38);
  229. //当从移位寄存器中读取状态数据时锁存字节选择信号
  230. assign LatchByte1_d2 = InProgress & ~WriteOp & BitCounter == 7'h37;
  231. assign LatchByte0_d2 = InProgress & ~WriteOp & BitCounter == 7'h3F;
  232. //连接时钟产生模块
  233. eth_clockgen
  234. clkgen(.Clk(Clk), .Reset(Reset), .Divider(Divider[7:0]), .MdcEn(MdcEn), .MdcEn_n(MdcEn_n), .Mdc(Mdc)
  235. );
  236. // 连接移位寄存器模块
  237. eth_shiftreg
  238. shftrg(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .Mdi(Mdi), .Fiad(Fiad), .Rgad(Rgad),
  239. .CtrlData(CtrlData), .WriteOp(WriteOp), .ByteSelect(ByteSelect), .LatchByte(LatchByte),
  240. .ShiftedBit(ShiftedBit), .Prsd(Prsd), .LinkFail(LinkFail)
  241. );
  242. // 连接输出控制模块
  243. eth_outputcontrol
  244. outctrl(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .InProgress(InProgress),
  245. .ShiftedBit(ShiftedBit), .BitCounter(BitCounter), .WriteOp(WriteOp), .NoPre(NoPre),
  246. .Mdo(Mdo), .MdoEn(MdoEn)
  247. );
  248. endmodule

更多回帖

发帖
×
20
完善资料,
赚取积分