gateware

A collection of little open source FPGA hobby projects
git clone http://frotz.net/git/gateware.git
Log | Files | Refs | README

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 }