IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> UDP发送部分的模块组装在一起 -> 正文阅读

[网络协议]UDP发送部分的模块组装在一起

之前写好了UDP ,IP ARP,MAC,ETHER层的各个发送和接收,今天时间有限之做了一件事,就是将发射部分拼装起来了。

方框图如下:

?这里简单说说我的思路,按照实际场景来说明:

0,如果我们的MAC接收到一个发给我们IP的ARP_REQUEST包,则要做两件事A,保存目标IP地址和物理地址到ARP_CACHE(这样我们发给他IP包时候就不需要询问他的物理地址了),B,返回一个ARP_REQPLY让对方知道我们的物理地址。这里说的物理地址就是48位MAC地址。

1,上述这条实际是接收部分实现,此模块留了一个接口就是上方的UPDATE_IP_MAC。可以说ARP_CACHE条目的更新就是通过接收部分解析ARP_REQUEST包和ARP_REPLY包来实现的。

2,我们要发送一个UDP数据包,传递给这个模块UDP报文数据流以及目标IP和目标端口以及自己的端口信息。

3,UDP信息进入UDP_IP模块,以此组装成UDP包,以及IP包,成为可以发送给MAC层的数据流。

4,MAC发送使用的是物流地址也就是48位的MAC地址,此模块内部设置状态机自动询问ARP_CACHE找出来对应的MAC地址。

5,如果没有找到,则通过给给ARP_GEN模块设置一写输入生成一个ARP_REQUEST的数据包,之后通过多路器传递给MAC_TX。

6,网络中的主机收到ARP_REQUEST后返回ARP_REPLY包汇报自己地址的。我们接收部分收到ARP_REPLY包后解析出来IP和MAC地址,通过上述框图的上方UPDATE_IP_UDP接口来传递给ARP_CACHE。

7,图中看见三个发送部分(其中最下面部分相应PING命令的ICMP_REPLY还没有写好),这个模块内部的状态机就是轮询这几个输入,根据情况控制多路器输出给MAC_TX进行发送。是不断轮询工作的。

8,这次轮询发现要发送的IP没有对应的物流地址,就发送了ARP_REQUEST数据包来请求物理地址,之后继续轮询。在若干毫秒后收到了ARP_REPLY,更新了ARP_CACHE。再次轮询的时候找到了物流地址,此时就会把这个滞留的IP包发出去。

9,在ARP_REQUEST发送到时候ARP_REPLY并更新ARP_CACHE期间这段时间会轮询很多次UDP_IP这路发射通道,为了防止每轮询以此就发送一个ARP_REQUEST,我这里设置了两个寄存器一个存储询问的IP地址一个计算时间,保证下次请求同一个IP地址的ARP_REQUEST数据包在一秒后发出。

10,这里我们能看到如果网络无法找到某个IP,则这个UDP会一直滞留没有做出错处理,这个可以先一放,如果实际应用需要处理这个问题了,可以再根据实际情况处理一下。由于采用状态机主控,寄存器以及模块之间的耦合在时序上比较松散灵活。

今天时间不够,写好代码了,编译检查过了,但是没有进行仿真。先上代码:



/*
mac_hub  mac_hub (
.clk(  ),
.rst(  ),
.cfg_my_ip(  ),
.cfg_my_mac(  ),  // local configuration

.s_udp_ip(  ), 
.s_udp_src_port(  ) ,
.s_udp_dst_port(  ) , 
.s_udp_tx_valid(  ) ,

.s_udp_tx_busy (  ),
.s_udp_tx_len(  ) ,
.s_udp_tx_dat(  ),  // udp port 
.s_udp_ip_id(  ),   
.s_udp_tx_start(  ) , // id in IP layer, may a const 

.arp_reply_dst_ip (  ), 
.arp_reply_dst_mac(  ) ,
.arp_reply_valid(  ) ,   
.arp_reply_ready(  ),// to send a arp_reply package   

.phy_tx_en (  ), 
.phy_tx_err (  ), 
.phy_tx_data(  )  , // gmii if 

.arp_cache_mac_in   (  ) ,
.arp_cache_ip_in(  )     ,
.arp_cache_wr_en(  )    // update arp cache from arp 

);
*/



module mac_hub (
input clk,rst,
input [31:0] cfg_my_ip,
input [47:0] cfg_my_mac,  // local configuration

input [31:0]s_udp_ip, 
input[15:0] s_udp_src_port ,s_udp_dst_port , 
input s_udp_tx_valid ,

output s_udp_tx_busy ,
input [15:0] s_udp_tx_len ,
input [7:0] s_udp_tx_dat,  // udp port 
input [15:0] s_udp_ip_id,   
input   s_udp_tx_start , // id in IP layer, may a const 

input [31:0] arp_reply_dst_ip , 
input [47:0] arp_reply_dst_mac ,
input arp_reply_valid ,   
output reg arp_reply_ready,// to send a arp_reply package   

output  phy_tx_en , phy_tx_err , 
output [7:0] phy_tx_data  , // gmii if 

input  [47:0] arp_cache_mac_in    ,
input  [31:0] arp_cache_ip_in     ,
input  arp_cache_wr_en    // update arp cache from arp 

);



reg [47:0]  arp_dst_mac ;
reg [31:0]  arp_dst_ip ;

reg arp_req0_rep1 , arp_s_valid    ;
wire arp_s_ready ;


reg arp_load ;
 
arp_gen  arp_gen (
.clk (clk ),
.rst(rst ) ,
 
.my_ip( cfg_my_ip ),
.my_mac( cfg_my_mac ),


.dst_ip( arp_dst_ip ),
.dst_mac( arp_dst_mac),
.req0_rep1(arp_req0_rep1 ) ,// request=0 ,reply=1
 
 
.arp_ack    ( mac_s_ack  ) ,
.arp_load   ( arp_load ) ,
.arp_data   ( arp_data ) ,
.arp_last   ( arp_last ) 

);

always @(posedge clk )if (rst)arp_load<=0; else case ( st ) (100+1) ,(300+1) : arp_load <=1;default arp_load<=0;endcase 
always @(posedge clk )if (rst) {arp_dst_mac,arp_dst_ip} <=0; else  case ( st ) 100 : {arp_dst_mac,arp_dst_ip} <= {  arp_reply_dst_mac , arp_reply_dst_ip };300:{arp_dst_mac,arp_dst_ip} <= {48'b0,s_udp_ip} ;endcase 
always @(posedge clk )if (rst)arp_req0_rep1<=0; else case (st)100:arp_req0_rep1<=1;300:arp_req0_rep1<=0;endcase 

/*


*/


 

reg [31:0] arp_cache_ip_req    ;
wire [47:0] arp_cache_mac_out  ;
wire arp_cache_req_done , arp_cache_req_hit ;
reg   arp_cache_req_en ;

arp_cache arp_cache(
.clk (clk ), 
.rst (rst ),
.ip_in( arp_cache_ip_in ),
.mac_in(  arp_cache_mac_in),
.wr_en( arp_cache_wr_en  ),
.wr_busy ( ),
.req_en (arp_cache_req_en),
.ip_req( arp_cache_ip_req ),
.mac_out( arp_cache_mac_out ),
.req_done(arp_cache_req_done ),
.req_hit( arp_cache_req_hit)
);

wire  [7:0]  udp_m_ip_tx_data ;
udp_ip_pack  udp_ip_pack (
		 .clk(clk ),
		 .rst(rst ),
		 .enable( udp_ip_enable  ),
		 .s_src_ip(cfg_my_ip ),
		 .s_dst_ip(s_udp_ip ),
		 .s_src_port(s_udp_src_port ),
		 .s_dst_port(s_udp_dst_port ), 
		 .s_tx_len   ( s_udp_tx_len ),
		 .s_tx_start ( s_udp_tx_start ),
		 .s_tx_busy  ( s_udp_tx_busy ),
		 .s_tx_dat   (s_udp_tx_dat ), 
		 .s_ip_id    (s_udp_ip_id ),  // from upper layer   
 		 
		 .m_ip_pack_valid (udp_m_ip_pack_valid),
		 .m_ip_tx_last(m_ip_tx_last  ),
		 .m_ip_tx_ack  (mac_s_ack )   ,
		 .m_ip_tx_data( m_ip_tx_data)	// to mac layer 		 
		 ); 
	
reg [47:0] mac_tx_dst_mac; always @ (posedge clk ) mac_tx_dst_mac  <= arp_cache_mac_out  ;
//reg [47:0] mac_tx_dst_mac; always @ (posedge clk )if (st ==220 ) mac_tx_dst_mac  <= arp_cache_mac_out  ;


reg [7:0]mac_s_ip_tx_data ;

localparam MAC_TYPE_IP  = 'H3421;
localparam MAC_TYPE_ARP = 'H5678;

reg [15:0]  mac_type = 0 ; always @ (posedge clk) case (st) 100,300:mac_type <= MAC_TYPE_ARP ; 200:mac_type <= MAC_TYPE_IP ; endcase
 
reg mac_s_valid ;
always @ (posedge clk) case (st) 103, 222,310  :mac_s_valid <= 1 ; default mac_s_valid <= 0 ; endcase 
reg mac_s_last;

mac_tx  mac_tx (
		 .clk(clk ) ,
		 .rst(rst ) ,
		 .s_valid( mac_s_valid ) ,
		 .s_last( mac_s_last ), 
		 .s_busy(mac_s_busy ) ,
		 .s_ack(mac_s_ack )   ,  
		 .s_ip_tx_data( mac_s_ip_tx_data) ,
		 .s_src_mac( cfg_my_mac ),
		 .s_dst_mac( mac_tx_dst_mac ),
		 .s_type( mac_type ), // 
		 
		 
		 .phy_tx_en( phy_tx_en ),
		 .phy_tx_err( phy_tx_err ),
		 .phy_tx_data( phy_tx_data ) 
		 );	

always @ (posedge clk ) arp_reply_ready <= st==112 ;

reg [31:0]  sending_arp_ip ;
reg [31:0]  sending_time_cntr ;

always @(posedge clk) arp_cache_ip_req <= s_udp_ip ;


localparam ARP_TIMEOUT = 1000*1000*125 ; 
always @(posedge clk) if (rst )sending_arp_ip <= 0 ; else case (st) 312:   sending_arp_ip<=arp_dst_ip ;endcase 
always @(posedge clk) if (rst )sending_time_cntr<= (1000*1000*125)  ; 
else if (st == 312)  sending_time_cntr  <= 32'h0;else  if (ARP_TIMEOUT!=sending_time_cntr)
sending_time_cntr<=sending_time_cntr+1;

wire arp_in_sending = (s_udp_ip == sending_arp_ip ) && ( sending_time_cntr != ARP_TIMEOUT ) ;


reg[7:0]st ; always@(posedge clk)if (rst)st<=0;else case (st)
0:st<=10;
10 : if (arp_reply_valid)st<=100;else st<=200; //鍙戦佷竴涓猘rp璇锋眰鍖
100,101,102,103:st<=st+1;//浣跨敤4涓懆鏈熷畬鎴愬彂閫佽缃
103: if (mac_s_busy==0)st<=111;
111: if (mac_s_busy==1)st<=112;
112: if (mac_s_busy==0)st<=113;
113: st<=200;

200: if (udp_m_ip_pack_valid==0) st<=400;else st<=210;
210: if (arp_cache_req_done) st<=(arp_cache_req_hit)?220:300;// with IP find out MAC  //
220: st<=221; //mac_tx_dst_mac  <= arp_cache_mac_out  ;
221: st<=222; //s_udp_tx_start=1 in this state otherwise will be 0 
222: if (mac_s_busy==0)st<=223;
223: if (mac_s_busy==1)st<=224; 
224: if (mac_s_busy==0)st<=225; 

// 3state prevous while connect upd_ip to mac_tx 
225: st<=300;
300: st<=301;//we need send a arp request 
301: st <= (arp_in_sending) ? 313:302; 
302,303,304,305,306,307,308,309:st<=st+1;
310: if (mac_s_busy==0)st<=311;
311: if (mac_s_busy==1)st<=312;
312: if (mac_s_busy==0)st<=313;//record sending ip 
313: st<=314;
314: st<=10; 
default st<=0; 
endcase 


always @* case (st)
100,101,102,103,111,112,200 , 300,301,302,303,304,305,306,307,308,309,310,311,312: begin mac_s_last <= arp_last ;mac_s_ip_tx_data <= arp_data;end 
220,221,22,223,224 :  begin mac_s_last <= m_ip_tx_last ;mac_s_ip_tx_data <= m_ip_tx_data;end 
default begin mac_s_last <= 0 ;mac_s_ip_tx_data <= 0;end 
endcase 


endmodule 




此模块暂时不进行仿真,明天看有时间再组装起来下图的模块,其中红框部分就是上述代码mac_hub,这样就整个设计彻底封装起来了(虽然暂时还没有实现ICMP回应),下一步就可以使用两个这样的模块(模拟两套以太网板子)进行UDP收发测试。

上图中MAC_RX传递给MAC_HUB的内容包含三部分 ARP_REPLY的发送,ICMP_REPLY的发送,以及ARP包解析出来的IP和物理地址的对应。

希望明天时间能够一些,可以组装在一起并完成两个板子互通的仿真。如果完成的话后天就可以上板子运行了。

上板子运行时候,先实现一下MAC层发送,用WIRESHARK查看一下接收,确保发送底层实现OK。再用PING命令PING咱们板子,虽然没有实现PING回复但是可以让我们电脑网卡发出ARP_REQUEST命令,我们在FPGA内部嵌入上逻辑分析仪,对比看到接收到序列完全正确就可以确保接受底层部分OK。

收发底层OK后剩下纯粹的RTL算法的成功是么有任何悬念:首先我们用的是同步时钟设计思路并且单时钟,其次在编写RTL时候可以思考了寄存器尽量少的扇出和尽量短的逻辑电路长度(尽量少的LUT串联级数),确保能跑到很高足够时钟频率。

下图是QUARTUS来看RTL连接,这样能直观看各线路的连接。

?下图是MAC_HUB部分的层次结构,另外也可以看到实际使用了很少的LOGIC ELEMENT和BLACK RAM 。

这里看到存储使用数量跟我们的定义的12位8BIT的内存数量不一致,应该是2048*8位,而我们看到只报出了使用4096位,这需要研究明白原因。

{{aAxvOXMOIvVUoXMxvoxiowMwWV8xxWTxoxOIOVIUUOvwVOUiIoUvvTMMVMwovWHWX8vOUOUVUwowVIoWwOMIViUIioOIWxmmMMHwMHHMiOWMmwUxiOMoiHIoVU8VvmvIWXTvvOvv8xvMovOWoVmmxoMM8UmooOTvvwUIoTwvmWUoiTw8VmvoHWwMIUWOixiowiUoiXwiwwMMIiIXHwUmOWUVmXXwV8iHWOTUiwTU8xwOoV8HVmTWZz}}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-12-08 14:09:51  更:2021-12-08 14:10:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:30:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码