| // |
| // Copyright (c) 1999 Thomas Coonan (tcoonan@mindspring.com) |
| // |
| // This source code is free software; you can redistribute it |
| // and/or modify it in source code form under the terms of the GNU |
| // General Public License as published by the Free Software |
| // Foundation; either version 2 of the License, or (at your option) |
| // any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| // |
| // |
| // 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 |
| // |
| // |
| // 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 |
| if (crc16_result !== crc16_expected) |
| begin |
| num_errors = num_errors + 1; |
| $display ("FAILED - Actual crc16_result = %h, Expected = %h", |
| crc16_result, crc16_expected); |
| end |
| |
| // **** TEST CRC16 |
| // |
| 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; |
| if (crc32_result !== crc32_expected) |
| begin |
| $display ("FAILED - Actual crc32_result = %h, Expected = %h", |
| crc32_result, crc32_expected); |
| num_errors = num_errors + 1; |
| end |
| |
| if(num_errors == 0) |
| $display("PASSED"); |
| 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 |
| |