新手上路
- 积分
- 49
- 金钱
- 49
- 注册时间
- 2016-12-9
- 在线时间
- 6 小时
|
关于skip_en 的赋值,只要满足条件就会被赋值为1(skip_en <= 1'b1),而且是只维持一个clk时钟周期,就又会被重新赋值为0(skip_en <= 1'b0),当skip_en被赋值1时,将启动组合逻辑next_state值的变化,然后next_state被posedge clk采样,赋值给cur_state,其实这里一直又个疑问,为什么skip_en赋1的值只维持一个clk周期的,就能被相同clk周期的上升沿猜到稳定数据,就感觉不可思议,硬件上具体时怎样实现的,建立、保持、Tco这些时间时怎样做到数据能保持如此稳定的,希望能解答下。
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cur_state <= st_idle;
else
cur_state <= next_state;
end
//解析数据状态跳转
always @(*) begin
next_state = st_idle;
case(cur_state)
st_idle : begin //等待接收前导码
if(skip_en)
next_state = st_preamble;
else
next_state = st_idle;
end
st_preamble : begin //接收前导码
if(skip_en)
next_state = st_eth_head;
else if(error_en)
next_state = st_rx_end;
else
next_state = st_preamble;
end
st_eth_head : begin //接收以太网帧头
if(skip_en)
next_state = st_ip_head;
else if(error_en)
next_state = st_rx_end;
else
next_state = st_eth_head;
end
st_ip_head : begin //接收IP首部
if(skip_en)
next_state = st_udp_head;
else if(error_en)
next_state = st_rx_end;
else
next_state = st_ip_head;
end
st_udp_head : begin //接收UDP首部
if(skip_en)
next_state = st_rx_data;
else
next_state = st_udp_head;
end
st_rx_data : begin //接收有效数据
if(skip_en)
next_state = st_rx_end;
else
next_state = st_rx_data;
end
st_rx_end : begin //接收结束
if(skip_en)
next_state = st_idle;
else
next_state = st_rx_end;
end
default : next_state = st_idle;
endcase
end
//解析以太网数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
skip_en <= 1'b0;
error_en <= 1'b0;
cnt <= 5'd0;
des_mac <= 48'd0;
eth_type <= 16'd0;
des_ip <= 32'd0;
ip_head_byte_num <= 6'd0;
udp_byte_num <= 16'd0;
data_byte_num <= 16'd0;
data_cnt <= 16'd0;
rec_en_cnt <= 2'd0;
rec_en <= 1'b0;
rec_data <= 32'd0;
rec_pkt_done <= 1'b0;
rec_byte_num <= 16'd0;
end
else begin
skip_en <= 1'b0;
error_en <= 1'b0;
rec_en <= 1'b0;
rec_pkt_done <= 1'b0;
case(cur_state)
st_idle : begin
if((rx_byte_val == 1'b1) && (rx_data == 8'h55))
skip_en <= 1'b1;
end
st_preamble : begin
if(rx_byte_val) begin //解析前导码
cnt <= cnt + 5'd1;
if((cnt < 5'd6) && (rx_data != 8'h55)) //7个8'h55
error_en <= 1'b1;
else if(cnt==5'd6) begin
cnt <= 5'd0;
if(rx_data==8'hd5) //1个8'hd5
skip_en <= 1'b1;
else
error_en <= 1'b1;
end
end
end
st_eth_head : begin
if(rx_byte_val) begin
cnt <= cnt + 5'b1;
if(cnt < 5'd6)
des_mac <= {des_mac[39:0],rx_data}; //目的MAC地址
else if(cnt == 5'd12)
eth_type[15:8] <= rx_data; //以太网协议类型
else if(cnt == 5'd13) begin
eth_type[7:0] <= rx_data;
cnt <= 5'd0;
//判断MAC地址是否为开发板MAC地址或者公共地址
if((des_mac == BOARD_MAC)
||(des_mac == 48'hff_ff_ff_ff_ff_ff))
skip_en <= 1'b1;
else
error_en <= 1'b1;
end
end
end
st_ip_head : begin
if(rx_byte_val) begin
cnt <= cnt + 5'd1;
if(cnt == 5'd0)
ip_head_byte_num <= {rx_data[3:0],2'd0};
else if((cnt >= 5'd16) && (cnt <= 5'd18))
des_ip <= {des_ip[23:0],rx_data}; //目的IP地址
else if(cnt == 5'd19) begin
des_ip <= {des_ip[23:0],rx_data};
//判断IP地址是否为开发板IP地址
if((des_ip[23:0] == BOARD_IP[31:8])
&& (rx_data == BOARD_IP[7:0])) begin
if(cnt == ip_head_byte_num - 1'b1) begin
skip_en <=1'b1;
cnt <= 5'd0;
end
end
else begin
//IP错误,停止解析数据
error_en <= 1'b1;
cnt <= 5'd0;
end
end
else if(cnt == ip_head_byte_num - 1'b1) begin
skip_en <=1'b1; //IP首部解析完成
cnt <= 5'd0;
end
end
end
st_udp_head : begin
if(rx_byte_val) begin
cnt <= cnt + 5'd1;
if(cnt == 5'd4)
udp_byte_num[15:8] <= rx_data; //解析UDP字节长度
else if(cnt == 5'd5)
udp_byte_num[7:0] <= rx_data;
else if(cnt == 5'd7) begin
//有效数据字节长度,(UDP首部8个字节,所以减去8)
data_byte_num <= udp_byte_num - 16'd8;
skip_en <= 1'b1;
cnt <= 5'd0;
end
end
end
st_rx_data : begin
//接收数据,转换成32bit
if(rx_byte_val) begin
data_cnt <= data_cnt + 16'd1;
rec_en_cnt <= rec_en_cnt + 2'd1;
if(data_cnt == data_byte_num - 16'd1) begin
skip_en <= 1'b1; //有效数据接收完成
data_cnt <= 16'd0;
rec_en_cnt <= 2'd0;
rec_pkt_done <= 1'b1;
rec_en <= 1'b1;
rec_byte_num <= data_byte_num;
end
//先收到的数据放在了rec_data的高位,所以当数据不是4的倍数时,
//低位数据为无效数据,可根据有效字节数来判断(rec_byte_num)
if(rec_en_cnt == 2'd0)
rec_data[31:24] <= rx_data;
else if(rec_en_cnt == 2'd1)
rec_data[23:16] <= rx_data;
else if(rec_en_cnt == 2'd2)
rec_data[15:8] <= rx_data;
else if(rec_en_cnt==2'd3) begin
rec_en <= 1'b1;
rec_data[7:0] <= rx_data;
end
end
end
st_rx_end : begin //单包数据接收完成
if(eth_rxdv == 1'b0 && skip_en == 1'b0)
skip_en <= 1'b1;
end
default : ;
endcase
end
end
|
|