// // Behavioral Verilog for CRC16 and CRC32 for use in a testbench. // // The specific polynomials and conventions regarding bit-ordering etc. // are specific to the Cable Modem DOCSIS protocol, but the general scheme // should be reusable for other types of CRCs with some fiddling. // // This CRC code works for a specific type of network protocol, and it // must do certain byte swappings, etc. You may need to play with it // for your protocol. Also, make sure the polynomials are what you // really want. This is obviously, not synthesizable - I just used this // in a testbench at one point. // // These tasks are crude and rely on some global parameters. They should // also read from a file, yada yada yada. It is probably better to do this // with a PLI call, but here it is anyway.. // // The test case includes a golden DOCSIS (Cable Modem) test message that // was captured in a lab. // // tom coonan, 1999. // module test_gencrc; // *** Buffer for the Golden Message *** reg [7:0] test_packet[0:54]; // *** Global parameter block for the CRC32 calculator. // parameter CRC32_POLY = 32'h04C11DB7; reg [ 7:0] crc32_packet[0:255]; integer crc32_length; reg [31:0] crc32_result; // *** Global parameter block for the CRC16 calculator. // parameter CRC16_POLY = 16'h1020; reg [ 7:0] crc16_packet[0:255]; integer crc16_length; reg [15:0] crc16_result; `define TEST_GENCRC `ifdef TEST_GENCRC // Call the main test task and then quit. // initial begin main_test; $finish; end `endif // **************************************************************** // * // * GOLDEN MESSAGE // * // * The golden message is a DOCSIS frame that was captured off // * the Broadcom reference design. It is a MAP message. It // * includes a HCS (crc 16) and a CRC32. // * // * // **************************************************************** // task initialize_test_packet; begin test_packet[00] = 8'hC2; // FC. HCS coverage starts here. test_packet[01] = 8'h00; // MACPARAM test_packet[02] = 8'h00; // MAC LEN test_packet[03] = 8'h30; // MAC LEN. HCS Coverage includes this byte and ends here. test_packet[04] = 8'hF2; // CRC16 (also known as HCS) test_packet[05] = 8'hCF; // CRC16 cont.. test_packet[06] = 8'h01; // Start of the IEEE payload. CRC32 covererage starts here. This is the DA field test_packet[07] = 8'hE0; // DA field cont.. test_packet[08] = 8'h2F; // DA field cont.. test_packet[09] = 8'h00; // DA field cont.. test_packet[10] = 8'h00; // DA field cont.. test_packet[11] = 8'h01; // DA field cont.. test_packet[12] = 8'h00; // SA field test_packet[13] = 8'h80; // SA field cont.. test_packet[14] = 8'h42; // SA field cont.. test_packet[15] = 8'h42; // SA field cont.. test_packet[16] = 8'h20; // SA field cont.. test_packet[17] = 8'h9E; // SA field cont.. test_packet[18] = 8'h00; // IEEE LEN field test_packet[19] = 8'h1E; // IEEE LEN field cont. test_packet[20] = 8'h00; // LLC field. test_packet[21] = 8'h00; // LLC field cont... test_packet[22] = 8'h03; // LLC field cont... test_packet[23] = 8'h01; // LLC field cont... test_packet[24] = 8'h03; // LLC field cont... This is also the TYPE, which indicates MAP. test_packet[25] = 8'h00; // LLC field cont... test_packet[26] = 8'h01; // Start of MAP message payload. test_packet[27] = 8'h01; // MAP message payload.. test_packet[28] = 8'h02; // MAP message payload.. test_packet[29] = 8'h00; // MAP message payload.. test_packet[30] = 8'h00; // MAP message payload.. test_packet[31] = 8'h18; // MAP message payload.. test_packet[32] = 8'hAA; // MAP message payload.. test_packet[33] = 8'h58; // MAP message payload.. test_packet[34] = 8'h00; // MAP message payload.. test_packet[35] = 8'h18; // MAP message payload.. test_packet[36] = 8'hA8; // MAP message payload.. test_packet[37] = 8'hA0; // MAP message payload.. test_packet[38] = 8'h02; // MAP message payload.. test_packet[39] = 8'h03; // MAP message payload.. test_packet[40] = 8'h03; // MAP message payload.. test_packet[41] = 8'h08; // MAP message payload.. test_packet[42] = 8'hFF; // MAP message payload.. test_packet[43] = 8'hFC; // MAP message payload.. test_packet[44] = 8'h40; // MAP message payload.. test_packet[45] = 8'h00; // MAP message payload.. test_packet[46] = 8'h00; // MAP message payload.. test_packet[47] = 8'h01; // MAP message payload.. test_packet[48] = 8'hC0; // MAP message payload.. test_packet[49] = 8'h14; // Last byte of MAP payload, last byte covered by CRC32. test_packet[50] = 8'hDD; // CRC32 Starts here test_packet[51] = 8'hBF; // CRC32 cont.. test_packet[52] = 8'hC1; // CRC32 cont.. test_packet[53] = 8'h2E; // Last byte of CRC32, last byte of DOCSIS. end endtask // ************************************************************************* // * // * Main test task. // * // * Use our primary "golden packet". Copy into the generic global // * variables that the low-level 'gencrc16' and 'gencrc32' tasks use. // * Comare against the expected values and report SUCCESS or FAILURE. // * // ************************************************************************* // task main_test; integer i, j; integer num_errors; reg [15:0] crc16_expected; reg [31:0] crc32_expected; begin num_errors = 0; // Initialize the Golden Message! // initialize_test_packet; // **** TEST CRC16 // $display ("Testing CRC16:"); // // Copy golden test_packet into the main crc16 buffer.. for (i=0; i<4; i=i+1) begin crc16_packet[i] = test_packet[i]; end crc16_expected = {test_packet[4], test_packet[5]}; crc16_length = 4; // Must tell test function the length gencrc16; // Call main test function $display (" Actual crc16_result = %h, Expected = %h", crc16_result, crc16_expected); if (crc16_result == crc16_expected) begin $display (" Success."); end else begin $display (" ERROR!!!"); num_errors = num_errors + 1; end // **** TEST CRC16 // $display ("Testing CRC32:"); j = 0; for (i=6; i<50; i=i+1) begin crc32_packet[j] = test_packet[i]; j = j + 1; end crc32_expected = {test_packet[50], test_packet[51], test_packet[52], test_packet[53]}; crc32_length = 44; gencrc32; $display (" Actual crc32_result = %h, Expected = %h", crc32_result, crc32_expected); if (crc32_result == crc32_expected) begin $display (" Success."); end else begin $display (" ERROR!!!"); num_errors = num_errors + 1; end $display ("\nDone. %0d Errors.", num_errors); $display ("\n"); end endtask // **************************************************************** // * // * Main working CRC tasks are: gencrc16, gencrc32. // * // * These tasks rely on some globals (see front of program). // * // **************************************************************** // Generate a (DOCSIS) CRC16. // // Uses the GLOBAL variables: // // Globals referenced: // parameter CRC16_POLY = 16'h1020; // reg [ 7:0] crc16_packet[0:255]; // integer crc16_length; // // Globals modified: // reg [15:0] crc16_result; // task gencrc16; integer byte, bit; reg msb; reg [7:0] current_byte; reg [15:0] temp; begin crc16_result = 16'hffff; for (byte = 0; byte < crc16_length; byte = byte + 1) begin current_byte = crc16_packet[byte]; for (bit = 0; bit < 8; bit = bit + 1) begin msb = crc16_result[15]; crc16_result = crc16_result << 1; if (msb != current_byte[bit]) begin crc16_result = crc16_result ^ CRC16_POLY; crc16_result[0] = 1; end end end // Last step is to "mirror" every bit, swap the 2 bytes, and then complement each bit. // // Mirror: for (bit = 0; bit < 16; bit = bit + 1) temp[15-bit] = crc16_result[bit]; // Swap and Complement: crc16_result = ~{temp[7:0], temp[15:8]}; end endtask // Generate a (DOCSIS) CRC32. // // Uses the GLOBAL variables: // // Globals referenced: // parameter CRC32_POLY = 32'h04C11DB7; // reg [ 7:0] crc32_packet[0:255]; // integer crc32_length; // // Globals modified: // reg [31:0] crc32_result; // task gencrc32; integer byte, bit; reg msb; reg [7:0] current_byte; reg [31:0] temp; begin crc32_result = 32'hffffffff; for (byte = 0; byte < crc32_length; byte = byte + 1) begin current_byte = crc32_packet[byte]; for (bit = 0; bit < 8; bit = bit + 1) begin msb = crc32_result[31]; crc32_result = crc32_result << 1; if (msb != current_byte[bit]) begin crc32_result = crc32_result ^ CRC32_POLY; crc32_result[0] = 1; end end end // Last step is to "mirror" every bit, swap the 4 bytes, and then complement each bit. // // Mirror: for (bit = 0; bit < 32; bit = bit + 1) temp[31-bit] = crc32_result[bit]; // Swap and Complement: crc32_result = ~{temp[7:0], temp[15:8], temp[23:16], temp[31:24]}; end endtask endmodule [ [ ['module', 'test_gencrc', ';'], [ [ 'reg', '[', '7', ':', '0', ']', ['test_packet', '[', '0', ':', '54', ']'], ';'], ['parameter', ['CRC32_POLY', '=', "32 'h 04C11DB7"], ';'], [ 'reg', '[', '7', ':', '0', ']', ['crc32_packet', '[', '0', ':', '255', ']'], ';'], ['integer', ['crc32_length'], ';'], ['reg', '[', '31', ':', '0', ']', ['crc32_result'], ';'], ['parameter', ['CRC16_POLY', '=', "16 'h 1020"], ';'], [ 'reg', '[', '7', ':', '0', ']', ['crc16_packet', '[', '0', ':', '255', ']'], ';'], ['integer', ['crc16_length'], ';'], ['reg', '[', '15', ':', '0', ']', ['crc16_result'], ';'], ['initial', ['begin', [['main_test', ';'], ['$finish', ';']], 'end']], [ 'task', 'initialize_test_packet', ';', [ 'begin', [ [[['test_packet', ['[', '00', ']']], '=', "8 'h C2"], ';'], [[['test_packet', ['[', '01', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '02', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '03', ']']], '=', "8 'h 30"], ';'], [[['test_packet', ['[', '04', ']']], '=', "8 'h F2"], ';'], [[['test_packet', ['[', '05', ']']], '=', "8 'h CF"], ';'], [[['test_packet', ['[', '06', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '07', ']']], '=', "8 'h E0"], ';'], [[['test_packet', ['[', '08', ']']], '=', "8 'h 2F"], ';'], [[['test_packet', ['[', '09', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '10', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '11', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '12', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '13', ']']], '=', "8 'h 80"], ';'], [[['test_packet', ['[', '14', ']']], '=', "8 'h 42"], ';'], [[['test_packet', ['[', '15', ']']], '=', "8 'h 42"], ';'], [[['test_packet', ['[', '16', ']']], '=', "8 'h 20"], ';'], [[['test_packet', ['[', '17', ']']], '=', "8 'h 9E"], ';'], [[['test_packet', ['[', '18', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '19', ']']], '=', "8 'h 1E"], ';'], [[['test_packet', ['[', '20', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '21', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '22', ']']], '=', "8 'h 03"], ';'], [[['test_packet', ['[', '23', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '24', ']']], '=', "8 'h 03"], ';'], [[['test_packet', ['[', '25', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '26', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '27', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '28', ']']], '=', "8 'h 02"], ';'], [[['test_packet', ['[', '29', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '30', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '31', ']']], '=', "8 'h 18"], ';'], [[['test_packet', ['[', '32', ']']], '=', "8 'h AA"], ';'], [[['test_packet', ['[', '33', ']']], '=', "8 'h 58"], ';'], [[['test_packet', ['[', '34', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '35', ']']], '=', "8 'h 18"], ';'], [[['test_packet', ['[', '36', ']']], '=', "8 'h A8"], ';'], [[['test_packet', ['[', '37', ']']], '=', "8 'h A0"], ';'], [[['test_packet', ['[', '38', ']']], '=', "8 'h 02"], ';'], [[['test_packet', ['[', '39', ']']], '=', "8 'h 03"], ';'], [[['test_packet', ['[', '40', ']']], '=', "8 'h 03"], ';'], [[['test_packet', ['[', '41', ']']], '=', "8 'h 08"], ';'], [[['test_packet', ['[', '42', ']']], '=', "8 'h FF"], ';'], [[['test_packet', ['[', '43', ']']], '=', "8 'h FC"], ';'], [[['test_packet', ['[', '44', ']']], '=', "8 'h 40"], ';'], [[['test_packet', ['[', '45', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '46', ']']], '=', "8 'h 00"], ';'], [[['test_packet', ['[', '47', ']']], '=', "8 'h 01"], ';'], [[['test_packet', ['[', '48', ']']], '=', "8 'h C0"], ';'], [[['test_packet', ['[', '49', ']']], '=', "8 'h 14"], ';'], [[['test_packet', ['[', '50', ']']], '=', "8 'h DD"], ';'], [[['test_packet', ['[', '51', ']']], '=', "8 'h BF"], ';'], [[['test_packet', ['[', '52', ']']], '=', "8 'h C1"], ';'], [[['test_packet', ['[', '53', ']']], '=', "8 'h 2E"], ';']], 'end'], 'endtask'], [ 'task', 'main_test', ';', ['integer', ['i'], ['j'], ';'], ['integer', ['num_errors'], ';'], ['reg', '[', '15', ':', '0', ']', ['crc16_expected'], ';'], ['reg', '[', '31', ':', '0', ']', ['crc32_expected'], ';'], [ 'begin', [ [[['num_errors'], '=', '0'], ';'], ['initialize_test_packet', ';'], ['$display', '(', '"Testing CRC16:"', ')', ';'], [ 'for', '(', [['i'], '=', '0'], ';', [['i'], '<', '4'], ';', [['i'], '=', ['i'], '+', '1'], ')', [ 'begin', [ [ [ ['crc16_packet', ['[', ['i'], ']']], '=', ['test_packet', ['[', ['i'], ']']]], ';']], 'end']], [ [ ['crc16_expected'], '=', [ '{', ['test_packet', ['[', '4', ']']], ['test_packet', ['[', '5', ']']], '}']], ';'], [[['crc16_length'], '=', '4'], ';'], ['gencrc16', ';'], [ '$display', '(', '" Actual crc16_result = %h, Expected = %h"', ['crc16_result'], ['crc16_expected'], ')', ';'], [ 'if', ['(', ['crc16_result'], '==', ['crc16_expected'], ')'], ['begin', [['$display', '(', '" Success."', ')', ';']], 'end'], 'else', [ 'begin', [ ['$display', '(', '" ERROR!!!"', ')', ';'], [[['num_errors'], '=', ['num_errors'], '+', '1'], ';']], 'end']], ['$display', '(', '"Testing CRC32:"', ')', ';'], [[['j'], '=', '0'], ';'], [ 'for', '(', [['i'], '=', '6'], ';', [['i'], '<', '50'], ';', [['i'], '=', ['i'], '+', '1'], ')', [ 'begin', [ [ [ ['crc32_packet', ['[', ['j'], ']']], '=', ['test_packet', ['[', ['i'], ']']]], ';'], [[['j'], '=', ['j'], '+', '1'], ';']], 'end']], [ [ ['crc32_expected'], '=', [ '{', ['test_packet', ['[', '50', ']']], ['test_packet', ['[', '51', ']']], ['test_packet', ['[', '52', ']']], ['test_packet', ['[', '53', ']']], '}']], ';'], [[['crc32_length'], '=', '44'], ';'], ['gencrc32', ';'], [ '$display', '(', '" Actual crc32_result = %h, Expected = %h"', ['crc32_result'], ['crc32_expected'], ')', ';'], [ 'if', ['(', ['crc32_result'], '==', ['crc32_expected'], ')'], ['begin', [['$display', '(', '" Success."', ')', ';']], 'end'], 'else', [ 'begin', [ ['$display', '(', '" ERROR!!!"', ')', ';'], [[['num_errors'], '=', ['num_errors'], '+', '1'], ';']], 'end']], [ '$display', '(', '"\\nDone. %0d Errors."', ['num_errors'], ')', ';'], ['$display', '(', '"\\n"', ')', ';']], 'end'], 'endtask'], [ 'task', 'gencrc16', ';', ['integer', ['byte'], ['bit'], ';'], ['reg', ['msb'], ';'], ['reg', '[', '7', ':', '0', ']', ['current_byte'], ';'], ['reg', '[', '15', ':', '0', ']', ['temp'], ';'], [ 'begin', [ [[['crc16_result'], '=', "16 'h ffff"], ';'], [ 'for', '(', [['byte'], '=', '0'], ';', [['byte'], '<', ['crc16_length']], ';', [['byte'], '=', ['byte'], '+', '1'], ')', [ 'begin', [ [ [ ['current_byte'], '=', ['crc16_packet', ['[', ['byte'], ']']]], ';'], [ 'for', '(', [['bit'], '=', '0'], ';', [['bit'], '<', '8'], ';', [['bit'], '=', ['bit'], '+', '1'], ')', [ 'begin', [ [ [['msb'], '=', ['crc16_result', ['[', '15', ']']]], ';'], [ [['crc16_result'], '=', ['crc16_result'], '<<', '1'], ';'], [ 'if', [ '(', ['msb'], '!=', ['current_byte', ['[', ['bit'], ']']], ')'], [ 'begin', [ [ [ ['crc16_result'], '=', ['crc16_result'], '^', ['CRC16_POLY']], ';'], [ [['crc16_result', ['[', '0', ']']], '=', '1'], ';']], 'end']]], 'end']]], 'end']], [ 'for', '(', [['bit'], '=', '0'], ';', [['bit'], '<', '16'], ';', [['bit'], '=', ['bit'], '+', '1'], ')', [ [ ['temp', ['[', '15', '-', ['bit'], ']']], '=', ['crc16_result', ['[', ['bit'], ']']]], ';']], [ [ ['crc16_result'], '=', '~', [ '{', ['temp', ['[', '7', '0', ']']], ['temp', ['[', '15', '8', ']']], '}']], ';']], 'end'], 'endtask'], [ 'task', 'gencrc32', ';', ['integer', ['byte'], ['bit'], ';'], ['reg', ['msb'], ';'], ['reg', '[', '7', ':', '0', ']', ['current_byte'], ';'], ['reg', '[', '31', ':', '0', ']', ['temp'], ';'], [ 'begin', [ [[['crc32_result'], '=', "32 'h ffffffff"], ';'], [ 'for', '(', [['byte'], '=', '0'], ';', [['byte'], '<', ['crc32_length']], ';', [['byte'], '=', ['byte'], '+', '1'], ')', [ 'begin', [ [ [ ['current_byte'], '=', ['crc32_packet', ['[', ['byte'], ']']]], ';'], [ 'for', '(', [['bit'], '=', '0'], ';', [['bit'], '<', '8'], ';', [['bit'], '=', ['bit'], '+', '1'], ')', [ 'begin', [ [ [['msb'], '=', ['crc32_result', ['[', '31', ']']]], ';'], [ [['crc32_result'], '=', ['crc32_result'], '<<', '1'], ';'], [ 'if', [ '(', ['msb'], '!=', ['current_byte', ['[', ['bit'], ']']], ')'], [ 'begin', [ [ [ ['crc32_result'], '=', ['crc32_result'], '^', ['CRC32_POLY']], ';'], [ [['crc32_result', ['[', '0', ']']], '=', '1'], ';']], 'end']]], 'end']]], 'end']], [ 'for', '(', [['bit'], '=', '0'], ';', [['bit'], '<', '32'], ';', [['bit'], '=', ['bit'], '+', '1'], ')', [ [ ['temp', ['[', '31', '-', ['bit'], ']']], '=', ['crc32_result', ['[', ['bit'], ']']]], ';']], [ [ ['crc32_result'], '=', '~', [ '{', ['temp', ['[', '7', '0', ']']], ['temp', ['[', '15', '8', ']']], ['temp', ['[', '23', '16', ']']], ['temp', ['[', '31', '24', ']']], '}']], ';']], 'end'], 'endtask']], 'endmodule']]