OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5262|回复: 1

[ALTERA] 关于采样时钟的如此无缝连接疑问

[复制链接]

8

主题

12

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2016-12-9
在线时间
6 小时
发表于 2020-3-14 23:35:41 | 显示全部楼层 |阅读模式
关于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

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

712

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2178
金钱
2178
注册时间
2018-8-27
在线时间
258 小时
发表于 2020-3-16 09:09:01 | 显示全部楼层
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 13:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表