尝试使用硬件电路来解释CRC计算(DS18B20或者DS18B22的CRC计算)
之前在培训讲解DS18B22的测试时,CRC计算都是以C语言进行讲解的。今天在练习Verilog的时候,觉得也可以使用硬件电路来讲解。
DS1820的CRC计算硬件电路示意图如下:
这个是示意图,方框代表寄存器,XOR代表异或门。Verilog的硬件描述如下:
1 module D_FF 2 ( 3 input wire D, 4 input wire clk, 5 input wire rst, 6 output reg Q 7 ); 8 always @ (posedge clk, posedge rst) 9 begin 10 if(rst) 11 Q = 0; 12 else 13 Q = D; 14 end 15 endmodule 16 17 module CRC_CHECK 18 ( 19 input wire in, 20 input wire clk, 21 input wire rst, 22 output wire [7:0] Q 23 ); 24 25 wire dff7_in, dff3_in, dff2_in; 26 27 xor xor0(dff7_in, in , Q[0]); 28 xor xor1(dff2_in, dff7_in, Q[3]); 29 xor xor2(dff3_in, dff7_in, Q[4]); 30 31 D_FF dff7(dff7_in, clk, rst, Q[7]); 32 D_FF dff6(Q[7] , clk, rst, Q[6]); 33 D_FF dff5(Q[6] , clk, rst, Q[5]); 34 D_FF dff4(Q[5] , clk, rst, Q[4]); 35 D_FF dff3(dff3_in, clk, rst, Q[3]); 36 D_FF dff2(dff2_in, clk, rst, Q[2]); 37 D_FF dff1(Q[2] , clk, rst, Q[1]); 38 D_FF dff0(Q[1] , clk, rst, Q[0]); 39 endmodule 40 41 module Test; 42 reg data; 43 reg clk; 44 reg rst; 45 wire [0:7] Q; 46 47 CRC_CHECK DUT(.in(data), .clk(clk), .rst(rst), .Q(Q)); 48 49 initial 50 begin 51 data = 0; 52 clk = 0; 53 rst = 0; 54 end 55 56 reg [0:63] in_data; 57 initial 58 begin 59 // 测试数据,包含CRC,所以有64位,注意是LSB到MSB的顺序 60 in_data = 64'b0100010011110000110110111110010000000000000000000000000010010110; 61 end 62 63 initial 64 begin 65 #3 rst = 1; 66 #3 rst = 0; 67 end 68 69 always 70 begin 71 #5 clk = ~clk; 72 end 73 74 integer i; 75 initial 76 begin 77 for(i = 0; i < 64; i = i + 1) 78 begin 79 @(posedge clk) data = in_data[i]; 80 end 81 end 82 83 initial 84 begin 85 $monitor($time," data=%b, Q=%b", data, Q); 86 #640 $stop; 87 end 88 endmodule
因为ATE读取数据的时候,是LSB在前,所以Testbench中定义的时候是[0:63]而不是[63:0]。在Questa中查看原理图,结果如下:
寄存器电路使用的D触发器,但是自动生成的电路中,寄存器的顺序有点颠倒,好像《数字设计-原理与实践》的作者吐槽过这个问题。这个不重要,这样原理图就能够和原理示意图对得上了。运行仿真,最终输出的结果为:
# 0 data=0, Q=xxxxxxxx # 3 data=0, Q=00000000 # 15 data=1, Q=00000000 # 25 data=0, Q=10001100 # 35 data=0, Q=01000110 # 45 data=0, Q=00100011 # 55 data=1, Q=10011101 # 65 data=0, Q=01001110 # 75 data=0, Q=00100111 # 85 data=1, Q=10011111 # 95 data=1, Q=01001111 # 105 data=1, Q=00100111 # 115 data=1, Q=00010011 # 125 data=0, Q=00001001 # 135 data=0, Q=10001000 # 145 data=0, Q=01000100 # 155 data=0, Q=00100010 # 165 data=1, Q=00010001 # 175 data=1, Q=00001000 # 185 data=0, Q=10001000 # 195 data=1, Q=01000100 # 205 data=1, Q=10101110 # 215 data=0, Q=11011011 # 225 data=1, Q=11100001 # 235 data=1, Q=01110000 # 245 data=1, Q=10110100 # 255 data=1, Q=11010110 # 265 data=1, Q=11100111 # 275 data=0, Q=01110011 # 285 data=0, Q=10110101 # 295 data=1, Q=11010110 # 305 data=0, Q=11100111 # 315 data=0, Q=11111111 # 325 data=0, Q=11110011 # 335 data=0, Q=11110101 # 345 data=0, Q=11110110 # 355 data=0, Q=01111011 # 365 data=0, Q=10110001 # 375 data=0, Q=11010100 # 385 data=0, Q=01101010 # 395 data=0, Q=00110101 # 405 data=0, Q=10010110 # 415 data=0, Q=01001011 # 425 data=0, Q=10101001 # 435 data=0, Q=11011000 # 445 data=0, Q=01101100 # 455 data=0, Q=00110110 # 465 data=0, Q=00011011 # 475 data=0, Q=10000001 # 485 data=0, Q=11001100 # 495 data=0, Q=01100110 # 505 data=0, Q=00110011 # 515 data=0, Q=10010101 # 525 data=0, Q=11000110 # 535 data=0, Q=01100011 # 545 data=0, Q=10111101 # 555 data=0, Q=11010010 # 565 data=1, Q=01101001 # 575 data=0, Q=00110100 # 585 data=0, Q=00011010 # 595 data=1, Q=00001101 # 605 data=0, Q=00000110 # 615 data=1, Q=00000011 # 625 data=1, Q=00000001 # 635 data=0, Q=00000000
因为只是简单的仿真练习,就先不从文件读取数据了。后续可以从文件读取数据,然后对多行数据进行计算来验证CRC的电路是否正确。
后续补充:出于演示目的,还可以使用Logsim动态演示,其仿真电路如下图所示。将数据输入存储器中,利用计数器改变地址,逐位输出给CRC计算电路。Logsim还是挺容易上手的。很可惜,后续没有再升级了。