CRC校验——一道乐鑫笔试题

乐鑫笔试

题目:请将下面这段 C 语言描述的串行处理过程,转换为单拍完成的并行处理,并用可综合的 Verilog 来描述。

unsigned char cal_table_high_first(unsigned char value) 
{
     unsigned char i; 
     unsigned char checksum = value;

          for (i=8; i>0; --i)  
            { 
                if (checksum & 0x80)
                        checksum = (checksum << 1) ^ 0x31;
                else
                        checksum = (checksum << 1);
            }

           return checksum;
}
C Code

可以看出其实为CRC校验 CRC-8:x^8+x^5+x^4+1  0x31(0x131)

算法C语言实现:

#include<stdio.h>
int main(){
    unsignedchar cal_table_high_first(unsignedcharvalue); 
    unsignedchar data;
    for (unsignedchar i = 0; i < 16;++i)
    {
         data= cal_table_high_first(i);
         printf("value =0x%0x:check_sum=0x%0x  \n", i, data);
    }
    getchar();
}
  
unsignedchar cal_table_high_first(unsignedcharvalue)
{
    unsignedchar i;
    unsigned  char check_sum = value;
    for (i = 8; i > 0;--i)
    {
         if (check_sum &0x80)
         {
             check_sum= (check_sum << 1) ^ 0x31;
         }
         else
         {
             check_sum= (check_sum << 1);
         }
    }
    return check_sum;
}
View Code

输出结果:

 1 value =0x0:check_sum=0x0
 2 value =0x1:check_sum=0x31
 3 value =0x2:check_sum=0x62
 4 value =0x3:check_sum=0x53
 5 value =0x4:check_sum=0xc4
 6 value =0x5:check_sum=0xf5
 7 value =0x6:check_sum=0xa6
 8 value =0x7:check_sum=0x97
 9 value =0x8:check_sum=0xb9
10 value =0x9:check_sum=0x88
11 value =0xa:check_sum=0xdb
12 value =0xb:check_sum=0xea
13 value =0xc:check_sum=0x7d
14 value =0xd:check_sum=0x4c
15 value =0xe:check_sum=0x1f
16 value =0xf:check_sum=0x2e
result

C语言作为参考模型,用于后续Verilog的功能仿真。

该算法逻辑如下:

输入一个8bit的数,首先判断最高位是否为1,如果为1则左移一位,并且和8‘b00110001异或;如果最高位不为1则左移一位。此过程执行8次。

 

此时我们来看一下异或操作的真值表

 

 我们可以看出:任何数与0异或都等于它本身,即0^x=x。所以我们可以把算法流程变换为:

 

 8'h31 = 8'b00110001, 8'h00 = 8'b00000000,设左移前最高位为M,可以将判断左移前最高位是否为1的过程省略,直接与8'b00MM000M异或,此时流程图可以简化为:

 

 由此,我们可以将循环解开,设输入为一个8bit数C[7:0],下面为解循环过程。

 

 根据上述结果,可以用verilog描述。

 1 module loop1(
 2    input clk,
 3    input rst_n,
 4    input [7:0] check_sum,
 5    output reg [7:0] check_sum_o
 6 );
 7 //reg [7:0] check_sum_o;
 8 always @ (posedge clk or negedge rst_n)
 9        if(!rst_n)
10               begin
11                      check_sum_o<= 8'h0;
12               end
13        else
14               begin
15                      check_sum_o[7]<= check_sum[3]^check_sum[2]^check_sum[5];
16                      check_sum_o[6]<= check_sum[2]^check_sum[1]^check_sum[4]^check_sum[7];
17                      check_sum_o[5]<= check_sum[1]^check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
18                      check_sum_o[4]<= check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
19                      check_sum_o[3]<= check_sum[3]^check_sum[7]^check_sum[6];
20                      check_sum_o[2]<= check_sum[2]^check_sum[6]^check_sum[5];
21                      check_sum_o[1]<= check_sum[1]^check_sum[5]^check_sum[4]^check_sum[7];
22                      check_sum_o[0]<= check_sum[0]^check_sum[4]^check_sum[3]^check_sum[6];
23               end
24       
25 endmodule
Verilog Code

testbench:

 1 module loop1_tb;
 2 reg clk;
 3 reg rst_n;
 4 reg [7:0] check_sum;
 5 wire [7:0] check_sum_o;
 6 always #1 clk=~clk;
 7 initial
 8 begin
 9 clk = 0;
10 rst_n = 0;
11 #10
12 rst_n = 1;
13 for (check_sum=0;check_sum<16;check_sum=check_sum+1)
14        begin
15        #2
16         //check_sum = i;
17         $display ("check_sum = %h",check_sum_o);
18         if (check_sum == 15) $stop;
19        end
20 //$stop;
21 end
22 loop1 loop1_i1(
23        .clk(clk),
24        .rst_n(rst_n),
25        .check_sum(check_sum),
26        .check_sum_o(check_sum_o)
27 );
28 endmodule
testbench

打印结果为:

 1 # check_sum = 00
 2 # check_sum = 31
 3 # check_sum = 62
 4 # check_sum = 53
 5 # check_sum = c4
 6 # check_sum = f5
 7 # check_sum = a6
 8 # check_sum = 97
 9 # check_sum = b9
10 # check_sum = 88
11 # check_sum = db
12 # check_sum = ea
13 # check_sum = 7d
14 # check_sum = 4c
15 # check_sum = 1f
16 # check_sum = 2e
result

loop2.v的实现和loop1.v类似,只是代码量更少。

 1 module loop2(
 2    input clk,
 3    input rst_n,
 4    input [7:0] check_sum,
 5    output  reg [7:0] check_sum_o
 6 );
 7 integer i;
 8 //reg [7:0] check_sum_o;
 9 reg [7:0] ccc;
10 always @ (posedge clk or negedge rst_n)
11        if(!rst_n)
12               begin
13                      check_sum_o= 8'h0;
14               end
15        else
16               begin
17            ccc = check_sum;
18                      for(i=0;i<8;i=i+1)
19                 begin
20                     ccc ={ccc[6:0],1'b0}^({8{ccc[7]}} & 8'h31);
21                 end
22            check_sum_o = ccc;
23               end
24       
25 endmodule
View Code

其实也可以将C语言函数封装成Verilog的function,然后在在单周期内进行赋值。

module loop3(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output  reg [7:0] check_sum_o
 
);
 
integer i;
 
function [7:0] cal_table_high_first;
       input[7:0] value;
       reg[7:0] ccc ;
       reg[7:0] flag ;
              begin
                                   ccc= value;
                                   for(i=0;i<8;i=i+1)
                                          begin
                                                 flag= ccc & 8'h80 ;
                                                 if(flag!= 0 ) ccc = (ccc <<1) ^ 8'h31 ;
                                                 elseccc = (ccc <<1)  ;
                                         
                                          end
                                   cal_table_high_first= ccc;
              end
 
endfunction
 
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o= 8'h0;
              end
       else
              begin
                    check_sum_o<= cal_table_high_first(check_sum) ;
              end
      
endmodule
View Code

综上,loop1.vloop2.v的主要贡献是解开了算法实现的if-else判断。至于loop3.v中,将C语言描述的功能封装成fucntion,直接单周期完成赋值的实现方式在逻辑综合后是否增加了if-else判断语句的硬件开销不在本文讨论范围内。

这和设计者施加的时序约束和综合工具算法有关。

 

转载于https://mp.weixin.qq.com/s/Q_SwSYjNiV53XdEXshoNRA

posted on 2021-04-06 11:28  一曲挽歌  阅读(531)  评论(0编辑  收藏  举报

导航