crctool.c (3960B)
1 // Copyright 2015, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 // Based on "A Practical Parallel CRC Generation Method" by Evgeni Stavinov, 5 // published in Circuit Cellar, January 2010 6 7 #include <stdio.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 uint32_t serial_crc(uint32_t crc, uint32_t poly, size_t nbits, uint32_t din) { 13 din = din ^ ((crc >> (nbits-1)) & 1); 14 crc <<= 1; 15 if (din) crc ^= poly; 16 return crc & (0xFFFFFFFF >> (32-nbits)); 17 } 18 19 uint32_t parallel_crc(uint32_t crc, uint32_t poly, size_t nbits, uint32_t din, size_t dbits, int LSB) { 20 for (size_t n = 0; n < dbits; n++) { 21 if (LSB) { 22 crc = serial_crc(crc, poly, nbits, din & 1); 23 din >>= 1; 24 } else { 25 crc = serial_crc(crc, poly, nbits, (din >> (dbits-1)) & 1); 26 din <<= 1; 27 } 28 } 29 return crc; 30 } 31 32 char* binary(uint32_t n, size_t bits) { 33 static char out[33]; 34 char *p = out; 35 while (bits-- > 0) { 36 *p++ = '0' + ((n >> bits) & 1); 37 } 38 *p = 0; 39 return out; 40 } 41 42 int main(int argc, char** argv) { 43 size_t crcsz = 5; 44 uint32_t poly = 5; 45 size_t dinsz = 4; 46 int reverse = 0; 47 int invert = 0; 48 int lsb = 0; 49 50 while (argc > 1) { 51 if (!strcmp(argv[1], "-help")) { 52 fprintf(stderr, "usage: crctool -poly=<hex> -crcsz=<bits> -dinsz=<bits> [-reverse] [-invert]\n"); 53 return 0; 54 } else if (!strcmp(argv[1], "-reverse")) { 55 reverse = 1; 56 } else if (!strcmp(argv[1], "-invert")) { 57 invert = 1; 58 } else if (!strncmp(argv[1], "-poly=", 6)) { 59 poly = strtoul(argv[1] + 6, NULL, 16); 60 } else if(!strncmp(argv[1], "-crcsz=", 7)) { 61 crcsz = strtoul(argv[1] + 7, NULL, 10); 62 } else if(!strncmp(argv[1], "-dinsz=", 7)) { 63 dinsz = strtoul(argv[1] + 7, NULL, 10); 64 } else { 65 fprintf(stderr, "error: unknown option: %s\n", argv[1]); 66 return -1; 67 } 68 argv++; 69 argc--; 70 } 71 if ((crcsz < 2) || (crcsz > 32)) { 72 fprintf(stderr, "error: crc size %zu unsupported\n", crcsz); 73 return -1; 74 } 75 if ((dinsz < 1) || (dinsz > crcsz)) { 76 fprintf(stderr, "error: din size %zu unsupported\n", dinsz); 77 return -1; 78 } 79 80 uint32_t h1[32]; 81 for (size_t n = 0; n < dinsz; n++) { 82 h1[n] = parallel_crc(0, poly, crcsz, 1 << n, dinsz, lsb); 83 //fprintf(stderr, "h1[%zu] = %s\n", n, binary(h1[n], crcsz)); 84 } 85 86 uint32_t h2[32]; 87 for (size_t n = 0; n < crcsz; n++) { 88 h2[n] = parallel_crc(1 << n, poly, crcsz, 0, dinsz, lsb); 89 //fprintf(stderr, "h2[%zu] = %s\n", n, binary(h2[n], crcsz)); 90 } 91 92 printf("// autogenerated by crctool -poly=%x -crcsz=%zu -dinsz=%zu%s%s\n\n", 93 poly, crcsz, dinsz, reverse ? " -reverse" : "", invert ? " -invert" : ""); 94 printf("module crc_%zu_%x_%zu(\n", crcsz, poly, dinsz); 95 printf("\tinput clk,\n"); 96 printf("\tinput rst,\n"); 97 printf("\tinput en,\n"); 98 printf("\tinput [%zu:0]din,\n", dinsz - 1); 99 printf("\toutput [%zu:0]crc\n", crcsz - 1); 100 printf("\t);\n" "\n" "reg [%zu:0]c;\n" "reg [%zu:0]n;\n" "\n", crcsz - 1, crcsz - 1); 101 if (reverse) { 102 printf("wire [%zu:0]d = {din[0]", dinsz - 1); 103 for (size_t n = 1; n < dinsz; n++) { 104 printf(",din[%zu]", n); 105 } 106 printf("};\n\n"); 107 printf("assign crc = %s{\n\tc[0]", invert ? "~" : ""); 108 for (size_t n = 1; n < crcsz; n++) { 109 if ((n % 8) == 0) printf("\n\t"); 110 printf(",c[%zu]", n); 111 } 112 printf("\n\t};\n\n"); 113 } else { 114 printf("wire [%zu:0]d = din;\n\n", dinsz - 1); 115 printf("assign crc = %sc;\n\n", invert ? "~" : ""); 116 } 117 printf("always_comb begin\n"); 118 for (size_t n = 0; n < crcsz; n++) { 119 char* op = " = "; 120 printf("\tn[%zu]", n); 121 uint32_t bit = 1 << n; 122 for (size_t i = 0; i < crcsz; i++) { 123 if (h2[i] & bit) { 124 printf("%sc[%zu]", op, i); 125 op = "^"; 126 } 127 } 128 for (size_t i = 0; i < dinsz; i++) { 129 if (h1[i] & bit) { 130 printf("%sd[%zu]", op, i); 131 op = "^"; 132 } 133 } 134 printf(";\n"); 135 } 136 137 printf( 138 "end\n" 139 "\n" 140 "always_ff @(posedge clk) begin\n" 141 "\tif (rst) begin\n" 142 "\t\tc <= %zu'h%X;\n" 143 "\tend else if (en) begin\n" 144 "\t\tc <= n;\n" 145 "\tend\n" 146 "end\n" 147 "\n" 148 "endmodule\n", crcsz, 0xFFFFFFFF >> (32 - crcsz)); 149 return 0; 150 }