mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
software: shell from original BIOS
This commit is contained in:
parent
ef0667d959
commit
73fce59631
8 changed files with 476 additions and 35 deletions
|
@ -18,11 +18,12 @@ bios.elf: linker.ld $(OBJECTS) libs
|
|||
bios-rescue.elf: linker-rescue.ld $(OBJECTS) libs
|
||||
|
||||
%.elf:
|
||||
$(LD) $(LDFLAGS) -T $< -N -o $@ $(OBJECTS) -L$(M2DIR)/software/libbase -lbase
|
||||
$(LD) $(LDFLAGS) -T $< -N -o $@ $(OBJECTS) -L$(M2DIR)/software/libbase -L$(M2DIR)/software/libextra -lbase -lextra
|
||||
chmod -x $@
|
||||
|
||||
libs:
|
||||
make -C $(M2DIR)/software/libbase
|
||||
make -C $(M2DIR)/software/libextra
|
||||
|
||||
.PHONY: clean libs
|
||||
|
||||
|
|
|
@ -1,19 +1,454 @@
|
|||
#include <stdio.h>
|
||||
#include <irq.h>
|
||||
#include <uart.h>
|
||||
/*
|
||||
* Milkymist SoC (Software)
|
||||
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
#include <stdio.h>
|
||||
#include <console.h>
|
||||
#include <string.h>
|
||||
#include <uart.h>
|
||||
#include <system.h>
|
||||
#include <board.h>
|
||||
#include <irq.h>
|
||||
#include <version.h>
|
||||
#include <extra/crc.h>
|
||||
|
||||
#include <hw/flash.h>
|
||||
|
||||
enum {
|
||||
CSR_IE = 1, CSR_IM, CSR_IP, CSR_ICC, CSR_DCC, CSR_CC, CSR_CFG, CSR_EBA,
|
||||
CSR_DC, CSR_DEBA, CSR_JTX, CSR_JRX, CSR_BP0, CSR_BP1, CSR_BP2, CSR_BP3,
|
||||
CSR_WP0, CSR_WP1, CSR_WP2, CSR_WP3,
|
||||
};
|
||||
|
||||
/* General address space functions */
|
||||
|
||||
#define NUMBER_OF_BYTES_ON_A_LINE 16
|
||||
static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
|
||||
{
|
||||
char c;
|
||||
|
||||
char *data = (char *)ptr;
|
||||
int line_bytes = 0, i = 0;
|
||||
|
||||
putsnonl("Memory dump:");
|
||||
while(count > 0){
|
||||
line_bytes =
|
||||
(count > NUMBER_OF_BYTES_ON_A_LINE)?
|
||||
NUMBER_OF_BYTES_ON_A_LINE : count;
|
||||
|
||||
printf("\n0x%08x ", addr);
|
||||
for(i=0;i<line_bytes;i++)
|
||||
printf("%02x ", *(unsigned char *)(data+i));
|
||||
|
||||
for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
|
||||
printf(" ");
|
||||
|
||||
printf(" ");
|
||||
|
||||
for(i=0;i<line_bytes;i++) {
|
||||
if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
|
||||
printf(".");
|
||||
else
|
||||
printf("%c", *(data+i));
|
||||
}
|
||||
|
||||
for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
|
||||
printf(" ");
|
||||
|
||||
data += (char)line_bytes;
|
||||
count -= line_bytes;
|
||||
addr += line_bytes;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void mr(char *startaddr, char *len)
|
||||
{
|
||||
char *c;
|
||||
unsigned int *addr;
|
||||
unsigned int length;
|
||||
|
||||
if(*startaddr == 0) {
|
||||
printf("mr <address> [length]\n");
|
||||
return;
|
||||
}
|
||||
addr = (unsigned *)strtoul(startaddr, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect address\n");
|
||||
return;
|
||||
}
|
||||
if(*len == 0) {
|
||||
length = 1;
|
||||
} else {
|
||||
length = strtoul(len, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect length\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dump_bytes(addr, length, (unsigned)addr);
|
||||
}
|
||||
|
||||
static void mw(char *addr, char *value, char *count)
|
||||
{
|
||||
char *c;
|
||||
unsigned int *addr2;
|
||||
unsigned int value2;
|
||||
unsigned int count2;
|
||||
unsigned int i;
|
||||
|
||||
if((*addr == 0) || (*value == 0)) {
|
||||
printf("mw <address> <value> [count]\n");
|
||||
return;
|
||||
}
|
||||
addr2 = (unsigned int *)strtoul(addr, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect address\n");
|
||||
return;
|
||||
}
|
||||
value2 = strtoul(value, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect value\n");
|
||||
return;
|
||||
}
|
||||
if(*count == 0) {
|
||||
count2 = 1;
|
||||
} else {
|
||||
count2 = strtoul(count, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect count\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i=0;i<count2;i++) *addr2++ = value2;
|
||||
}
|
||||
|
||||
static void mc(char *dstaddr, char *srcaddr, char *count)
|
||||
{
|
||||
char *c;
|
||||
unsigned int *dstaddr2;
|
||||
unsigned int *srcaddr2;
|
||||
unsigned int count2;
|
||||
unsigned int i;
|
||||
|
||||
if((*dstaddr == 0) || (*srcaddr == 0)) {
|
||||
printf("mc <dst> <src> [count]\n");
|
||||
return;
|
||||
}
|
||||
dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect destination address\n");
|
||||
return;
|
||||
}
|
||||
srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect source address\n");
|
||||
return;
|
||||
}
|
||||
if(*count == 0) {
|
||||
count2 = 1;
|
||||
} else {
|
||||
count2 = strtoul(count, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect count\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
|
||||
}
|
||||
|
||||
static void crc(char *startaddr, char *len)
|
||||
{
|
||||
char *c;
|
||||
char *addr;
|
||||
unsigned int length;
|
||||
|
||||
if((*startaddr == 0)||(*len == 0)) {
|
||||
printf("crc <address> <length>\n");
|
||||
return;
|
||||
}
|
||||
addr = (char *)strtoul(startaddr, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect address\n");
|
||||
return;
|
||||
}
|
||||
length = strtoul(len, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect length\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("CRC32: %08x\n", crc32((unsigned char *)addr, length));
|
||||
}
|
||||
|
||||
/* processor registers */
|
||||
static int parse_csr(const char *csr)
|
||||
{
|
||||
if(!strcmp(csr, "ie")) return CSR_IE;
|
||||
if(!strcmp(csr, "im")) return CSR_IM;
|
||||
if(!strcmp(csr, "ip")) return CSR_IP;
|
||||
if(!strcmp(csr, "icc")) return CSR_ICC;
|
||||
if(!strcmp(csr, "dcc")) return CSR_DCC;
|
||||
if(!strcmp(csr, "cc")) return CSR_CC;
|
||||
if(!strcmp(csr, "cfg")) return CSR_CFG;
|
||||
if(!strcmp(csr, "eba")) return CSR_EBA;
|
||||
if(!strcmp(csr, "dc")) return CSR_DC;
|
||||
if(!strcmp(csr, "deba")) return CSR_DEBA;
|
||||
if(!strcmp(csr, "jtx")) return CSR_JTX;
|
||||
if(!strcmp(csr, "jrx")) return CSR_JRX;
|
||||
if(!strcmp(csr, "bp0")) return CSR_BP0;
|
||||
if(!strcmp(csr, "bp1")) return CSR_BP1;
|
||||
if(!strcmp(csr, "bp2")) return CSR_BP2;
|
||||
if(!strcmp(csr, "bp3")) return CSR_BP3;
|
||||
if(!strcmp(csr, "wp0")) return CSR_WP0;
|
||||
if(!strcmp(csr, "wp1")) return CSR_WP1;
|
||||
if(!strcmp(csr, "wp2")) return CSR_WP2;
|
||||
if(!strcmp(csr, "wp3")) return CSR_WP3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcsr(char *csr)
|
||||
{
|
||||
unsigned int csr2;
|
||||
register unsigned int value;
|
||||
|
||||
if(*csr == 0) {
|
||||
printf("rcsr <csr>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
csr2 = parse_csr(csr);
|
||||
if(csr2 == 0) {
|
||||
printf("incorrect csr\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(csr2) {
|
||||
case CSR_IE: asm volatile ("rcsr %0,ie":"=r"(value)); break;
|
||||
case CSR_IM: asm volatile ("rcsr %0,im":"=r"(value)); break;
|
||||
case CSR_IP: asm volatile ("rcsr %0,ip":"=r"(value)); break;
|
||||
case CSR_CC: asm volatile ("rcsr %0,cc":"=r"(value)); break;
|
||||
case CSR_CFG: asm volatile ("rcsr %0,cfg":"=r"(value)); break;
|
||||
case CSR_EBA: asm volatile ("rcsr %0,eba":"=r"(value)); break;
|
||||
case CSR_DEBA: asm volatile ("rcsr %0,deba":"=r"(value)); break;
|
||||
case CSR_JTX: asm volatile ("rcsr %0,jtx":"=r"(value)); break;
|
||||
case CSR_JRX: asm volatile ("rcsr %0,jrx":"=r"(value)); break;
|
||||
default: printf("csr write only\n"); return;
|
||||
}
|
||||
|
||||
printf("%08x\n", value);
|
||||
}
|
||||
|
||||
static void wcsr(char *csr, char *value)
|
||||
{
|
||||
char *c;
|
||||
unsigned int csr2;
|
||||
register unsigned int value2;
|
||||
|
||||
if((*csr == 0) || (*value == 0)) {
|
||||
printf("wcsr <csr> <address>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
csr2 = parse_csr(csr);
|
||||
if(csr2 == 0) {
|
||||
printf("incorrect csr\n");
|
||||
return;
|
||||
}
|
||||
value2 = strtoul(value, &c, 0);
|
||||
if(*c != 0) {
|
||||
printf("incorrect value\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(csr2) {
|
||||
case CSR_IE: asm volatile ("wcsr ie,%0"::"r"(value2)); break;
|
||||
case CSR_IM: asm volatile ("wcsr im,%0"::"r"(value2)); break;
|
||||
case CSR_ICC: asm volatile ("wcsr icc,%0"::"r"(value2)); break;
|
||||
case CSR_DCC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
|
||||
case CSR_EBA: asm volatile ("wcsr eba,%0"::"r"(value2)); break;
|
||||
case CSR_DC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
|
||||
case CSR_DEBA: asm volatile ("wcsr deba,%0"::"r"(value2)); break;
|
||||
case CSR_JTX: asm volatile ("wcsr jtx,%0"::"r"(value2)); break;
|
||||
case CSR_JRX: asm volatile ("wcsr jrx,%0"::"r"(value2)); break;
|
||||
case CSR_BP0: asm volatile ("wcsr bp0,%0"::"r"(value2)); break;
|
||||
case CSR_BP1: asm volatile ("wcsr bp1,%0"::"r"(value2)); break;
|
||||
case CSR_BP2: asm volatile ("wcsr bp2,%0"::"r"(value2)); break;
|
||||
case CSR_BP3: asm volatile ("wcsr bp3,%0"::"r"(value2)); break;
|
||||
case CSR_WP0: asm volatile ("wcsr wp0,%0"::"r"(value2)); break;
|
||||
case CSR_WP1: asm volatile ("wcsr wp1,%0"::"r"(value2)); break;
|
||||
case CSR_WP2: asm volatile ("wcsr wp2,%0"::"r"(value2)); break;
|
||||
case CSR_WP3: asm volatile ("wcsr wp3,%0"::"r"(value2)); break;
|
||||
default: printf("csr read only\n"); return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init + command line */
|
||||
|
||||
static void help()
|
||||
{
|
||||
puts("Milkymist(tm) BIOS");
|
||||
puts("Don't know what to do? Try 'flashboot'.\n");
|
||||
puts("Available commands:");
|
||||
puts("mr - read address space");
|
||||
puts("mw - write address space");
|
||||
puts("mc - copy address space");
|
||||
puts("crc - compute CRC32 of a part of the address space");
|
||||
puts("rcsr - read processor CSR");
|
||||
puts("wcsr - write processor CSR");
|
||||
puts("version - display version");
|
||||
puts("reboot - system reset");
|
||||
puts("reconf - reload FPGA configuration");
|
||||
}
|
||||
|
||||
static char *get_token(char **str)
|
||||
{
|
||||
char *c, *d;
|
||||
|
||||
c = (char *)strchr(*str, ' ');
|
||||
if(c == NULL) {
|
||||
d = *str;
|
||||
*str = *str+strlen(*str);
|
||||
return d;
|
||||
}
|
||||
*c = 0;
|
||||
d = *str;
|
||||
*str = c+1;
|
||||
return d;
|
||||
}
|
||||
|
||||
static void do_command(char *c)
|
||||
{
|
||||
char *token;
|
||||
|
||||
token = get_token(&c);
|
||||
|
||||
if(strcmp(token, "mr") == 0) mr(get_token(&c), get_token(&c));
|
||||
else if(strcmp(token, "mw") == 0) mw(get_token(&c), get_token(&c), get_token(&c));
|
||||
else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c));
|
||||
else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
|
||||
|
||||
else if(strcmp(token, "version") == 0) puts(VERSION);
|
||||
else if(strcmp(token, "reboot") == 0) reboot();
|
||||
else if(strcmp(token, "reconf") == 0) reconf();
|
||||
|
||||
else if(strcmp(token, "help") == 0) help();
|
||||
|
||||
else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
|
||||
else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
|
||||
|
||||
else if(strcmp(token, "") != 0)
|
||||
printf("Command not found\n");
|
||||
}
|
||||
|
||||
int rescue;
|
||||
extern unsigned int _edata;
|
||||
|
||||
static void crcbios()
|
||||
{
|
||||
unsigned int offset_bios;
|
||||
unsigned int length;
|
||||
unsigned int expected_crc;
|
||||
unsigned int actual_crc;
|
||||
|
||||
/*
|
||||
* _edata is located right after the end of the flat
|
||||
* binary image. The CRC tool writes the 32-bit CRC here.
|
||||
* We also use the address of _edata to know the length
|
||||
* of our code.
|
||||
*/
|
||||
offset_bios = rescue ? FLASH_OFFSET_RESCUE_BIOS : FLASH_OFFSET_REGULAR_BIOS;
|
||||
expected_crc = _edata;
|
||||
length = (unsigned int)&_edata - offset_bios;
|
||||
actual_crc = crc32((unsigned char *)offset_bios, length);
|
||||
if(expected_crc == actual_crc)
|
||||
printf("I: BIOS CRC passed (%08x)\n", actual_crc);
|
||||
else {
|
||||
printf("W: BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
|
||||
printf("W: The system will continue, but expect problems.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_mac()
|
||||
{
|
||||
unsigned char *macadr = (unsigned char *)FLASH_OFFSET_MAC_ADDRESS;
|
||||
|
||||
printf("I: MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", macadr[0], macadr[1], macadr[2], macadr[3], macadr[4], macadr[5]);
|
||||
}
|
||||
|
||||
static const char banner[] =
|
||||
"\nMILKYMIST(tm) v"VERSION" BIOS http://www.milkymist.org\n"
|
||||
"(c) Copyright 2007-2012 Sebastien Bourdeauducq\n\n"
|
||||
"This program is free software: you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation, version 3 of the License.\n";
|
||||
|
||||
static void readstr(char *s, int size)
|
||||
{
|
||||
char c[2];
|
||||
int ptr;
|
||||
|
||||
c[1] = 0;
|
||||
ptr = 0;
|
||||
while(1) {
|
||||
c[0] = readchar();
|
||||
switch(c[0]) {
|
||||
case 0x7f:
|
||||
case 0x08:
|
||||
if(ptr > 0) {
|
||||
ptr--;
|
||||
putsnonl("\x08 \x08");
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
s[ptr] = 0x00;
|
||||
putsnonl("\n");
|
||||
return;
|
||||
default:
|
||||
putsnonl(c);
|
||||
s[ptr] = c[0];
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int i, char **c)
|
||||
{
|
||||
char buffer[64];
|
||||
|
||||
rescue = !((unsigned int)main > FLASH_OFFSET_REGULAR_BIOS);
|
||||
|
||||
irq_setmask(0);
|
||||
irq_setie(1);
|
||||
uart_init();
|
||||
|
||||
printf("Hello World with IRQs\n");
|
||||
|
||||
printf(banner);
|
||||
crcbios();
|
||||
|
||||
if(rescue)
|
||||
printf("I: Booting in rescue mode\n");
|
||||
|
||||
print_mac();
|
||||
while(1) {
|
||||
c = uart_read();
|
||||
printf("You typed: %c\n", c);
|
||||
putsnonl("\e[1mBIOS>\e[0m ");
|
||||
readstr(buffer, 64);
|
||||
do_command(buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn);
|
|||
char readchar(void);
|
||||
int readchar_nonblock(void);
|
||||
|
||||
int puts(const char *s);
|
||||
void putsnonl(const char *s);
|
||||
|
||||
#endif /* __CONSOLE_H */
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
int putchar(int c);
|
||||
int puts(const char *s);
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
int scnprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
int sprintf(char *buf, const char *fmt, ...);
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include <console.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <irq.h>
|
||||
#include <hw/interrupts.h>
|
||||
|
||||
static console_write_hook write_hook;
|
||||
static console_read_hook read_hook;
|
||||
|
@ -37,11 +35,12 @@ void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn)
|
|||
read_nonblock_hook = rn;
|
||||
}
|
||||
|
||||
static void writechar(char c)
|
||||
int putchar(int c)
|
||||
{
|
||||
uart_write(c);
|
||||
if(write_hook != NULL)
|
||||
write_hook(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
char readchar(void)
|
||||
|
@ -62,34 +61,20 @@ int readchar_nonblock(void)
|
|||
|
||||
int puts(const char *s)
|
||||
{
|
||||
unsigned int oldmask;
|
||||
|
||||
oldmask = irq_getmask();
|
||||
irq_setmask(IRQ_UART); // HACK: prevent UART data loss
|
||||
|
||||
while(*s) {
|
||||
writechar(*s);
|
||||
putchar(*s);
|
||||
s++;
|
||||
}
|
||||
writechar('\n');
|
||||
|
||||
irq_setmask(oldmask);
|
||||
putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
|
||||
void putsnonl(const char *s)
|
||||
{
|
||||
unsigned int oldmask;
|
||||
|
||||
oldmask = irq_getmask();
|
||||
irq_setmask(IRQ_UART); // HACK: prevent UART data loss
|
||||
|
||||
while(*s) {
|
||||
writechar(*s);
|
||||
putchar(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
irq_setmask(oldmask);
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...)
|
||||
|
|
18
software/libextra/Makefile
Normal file
18
software/libextra/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
M2DIR=../..
|
||||
include $(M2DIR)/software/include.mak
|
||||
|
||||
OBJECTS=crc16.o crc32.o
|
||||
|
||||
all: libextra.a
|
||||
|
||||
# pull in dependency info for *existing* .o files
|
||||
-include $(OBJECTS:.o=.d)
|
||||
|
||||
libextra.a: $(OBJECTS)
|
||||
$(AR) clr libextra.a $(OBJECTS)
|
||||
$(RANLIB) libextra.a
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(OBJECTS:.o=.d) libextra.a .*~ *~
|
|
@ -1,4 +1,4 @@
|
|||
#include <crc.h>
|
||||
#include <extra/crc.h>
|
||||
|
||||
static const unsigned int crc16_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include <crc.h>
|
||||
#include <extra/crc.h>
|
||||
|
||||
static const unsigned int crc_table[256] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
|
|
Loading…
Reference in a new issue